Partial-Object updates

Feb 10, 2011 at 5:09 AM
Edited Feb 10, 2011 at 5:10 AM

I need to add a new property (FirmNumber, a uint) to an existing domain, which seems like a perfect place for a partial-object operation.  I've extracted all the items, set their FirmNumber property to the desired value, and pushed them back to to the cloud with PutAttributes.  The new property of the desired value indeed made it, but it cleared all the other properties.  I would really appreciate an example of how to it correctly.  Thanks in advance...

 

Coordinator
Feb 10, 2011 at 7:05 AM
Edited Feb 10, 2011 at 7:05 AM

What version are you using? It sounds like you're running into this issue fixed in 5.1.

Feb 10, 2011 at 5:33 PM
Edited Feb 11, 2011 at 7:52 PM

<Thank you - that certainly solved most of it.  I now can't seem to figure out how to modify a property.>

Note: this example has been edited from the original posting to show the resulting (working) code.

    List<PropertyValues> props = new List<PropertyValues>(); // list of properties needing to be set or updated

    foreach(var cf in caseFiles)

            PropertyValues pv = Savant.GetAttributes<CaseFile>(cf.FileID, "FirmNumber");
            if (pv == null)
            {   // the attribute hasn't ever been set for this record
                pv = new PropertyValues(cf.FileID);
                pv["FirmNumber"] = firmNumber;
                props.Add(pv);
            }
            else
            {   // the attribute exists and may need to be modified
                uint pVal = (uint)pv["FirmNumber"];
                if (pVal != desiredValue)
                {
                    pv["FirmNumber"] = (uint) desiredValue;  // a cast is here as a reminder in case desiredValue is numeric

                    props.Add(pv);
                }

           }

    }

            // if we found any that need added or updated, send them
            if (props.Count > 0)
                Savant.PutAttributes<CaseFile>(props.ToArray());

Coordinator
Feb 11, 2011 at 4:32 AM

What you're doing should work. I've done the same thing many times in my own code. You don't need to cast desiredValue to anything, but you do need to call Savant.PutAttributes() for the update to be persisted.

If you can produce a self-contained test case that demonstrates this incorrect behavior I'd love to see it.

Feb 11, 2011 at 7:42 PM
Edited Feb 11, 2011 at 8:46 PM

The casts were leftovers from attempts while using the older version, and with them removed everything with a GUID ItemName works.

I have edited the posted example to show the working code for that domain.

I have one domain with an ItemName of type string (it has worked well for over a year).

When I call GetAttributes I get a System.NullReferenceException at Coditate.Savant.PropertyValues.Copy(PropertyValues from, PropertyValues to). 

If I create a new PropertyValue and call PutAttributes, I get this exception:

"Message=allValues[0] has a problem: Invalid ItemName type. The ItemName 'CountryOfResidence' is expected to be a 'System.Guid' but is actually a 'System.String' at Coditate.Savant.SimpleSavant.PutAttributes[T](PropertyValues[] values)

 

Coordinator
Feb 12, 2011 at 12:36 AM

It looks like you could only get the NullReferenceException if you first loaded the entire object and then loaded a single attribute that did not exist. The error happens when Savant attempts to update the already cached data with newly retrieved attributes--which in this case are null. A workaround would be to either turn off caching during these partial-object updates or invoke SavantConfig.Cache.Flush() before the call.

I've created an issue to track this here.

To help you further I'll need to see more of the code and the full stack trace. There should be no problem with a string ItemName as the unit and system tests use a variety of item name types.

Coordinator
Feb 12, 2011 at 5:49 PM

There are actually two completely separate issues here: the NullReferenceException which is documented by this issue and the "Invalid ItemName type" error.

From the code sample you posted on the issue I see that you are reading values using one data class as the generic argument and writing them using a different data class. When using PutAttributes you need to be sure the ItemMapping you're using is in sync with the PropertyValues collection. It looks like you are probably getting the Invalid ItemName error because they are not in synch.

You should read through the documentation on Typeless operations because you probably need to manually build your ItemMapping and use a typeless operation to perform this conversion. You may also want to read other discussion threads where this kind of thing is discussed. See here and here.

If you still think something is working incorrectly please provide a complete and self-contained test case that demonstrates the incorrect behavior. I can't be sure what is happening without also seeing the data classes and setup code.