anthonyreilly / NetCoreForce

Salesforce REST API toolkit for .NET Standard and .NET Core
MIT License
110 stars 63 forks source link

updating a field to a null value #54

Open JanSenkowski opened 1 year ago

JanSenkowski commented 1 year ago

Hey is there a way to set a field to null when updating a sf-object?

VanceKInGa commented 1 year ago

I hit the same issue. I'm playing around with JSON attributes for null handling, but no luck yet. This is a big issue with this toolkit, IMHO.

I've tried the following on the object: [JsonObject(ItemNullValueHandling = NullValueHandling.Include)]. And this on an individual field: [JsonProperty(PropertyName = "Skills__c", NullValueHandling = NullValueHandling.Include)]

NOTE: (after more research) This appears to be a limitation of the SF API not the toolkit, however, there is a way around it using fieldsToNull.

In this SF Idea

VanceKInGa commented 1 year ago

I have found that the framework was ignoring null values on serializing the REST payload to send to SF. I am working on a modification that will allow you to specify which fields it should send even if null for each object type.

anthonyreilly commented 1 year ago

The SOAP api has a FieldsToNull property to address this, but I never found an equivalent in the REST api. Dropping the nulls was made the default behavior since that addressed the most typical use case of partial object updates. I'll need to test if if accepts explicit nulls, if so maybe adding an optional fieldstonull parameter on updates to control null handling on a per-property basis might be the way to go

anthonyreilly commented 1 year ago

@VanceKInGa I just tried something that looks like it will work using two options - either globally re-enabling null serialization (which is a bit dangerous) or using a fieldsToNull property in the update call to selectively null out properties to emulate the SOAP API's approach. I've got a working proof of concept that is testing good so far, so I think I'll be able to include this in a 4.0 Beta 2 soon

await client.UpdateRecord<SfAccount>(SfAccount.SObjectTypeName, account.Id, account, ignoreNulls: true, fieldsToNull: new List<string>(){"description"});

VanceKInGa commented 1 year ago

@anthonyreilly, I have a solution working but am finalizing the implementation as I put it in place in our API. If you send a null via the REST API it will null out the field in SF, but as you mentioned, you can't just do that for the entire object because you would wipe out fields you hadn't previously queried.

My approach uses a list of fields that should be serialized even if null, which means it will not serialize any other null values. You can set these prior to an update, or...

In conjunction with this change, I created a QueryBuilder class that can optionally be used to create a query using non-hardcoded SOQL queries. It automatically puts all the fields pulled into the list of fields that should be set to null on an update with each query built.

At it's most basic usage, it is something like this: QueryBuilder query = new QueryBuilder(client, typeof(SfContact), SfContact.SObjectTypeName, new List { nameof(SfContact.Id), nameof(SfContact.ProviderExternalId), nameof(SfContact.MobilePhone), nameof(SfContact.MailingStreet), nameof(SfContact.MailingCity), nameof(SfContact.MailingState) } );

anthonyreilly commented 1 year ago

@VanceKInGa I've added the fieldsToNull parameter to the update/create methods - it sends that down to the serialization contractresolver to control the per-property serialization. These changes are currently in the dev branch with partial test coverage. (I should have used nameof in the tests like you did, I'll update that)

https://github.com/anthonyreilly/NetCoreForce/blob/cc4be924f61007dc6ed007282bd4fb2199dbe62b/src/NetCoreForce.Client/ForceClient.cs#L494

https://github.com/anthonyreilly/NetCoreForce/blob/cc4be924f61007dc6ed007282bd4fb2199dbe62b/src/NetCoreForce.Client/Serializer/CreateableContractResolver.cs

That QueryBuilder looks interesting as well - whenever you have that ready I'd like to see it

VanceKInGa commented 1 year ago

I reworked my QueryBuilder changes based on your null handling in the client. It automatically tracks the fields to set to null based on the ones pulled.

I am ready to create a new branch (dev-QueryBuilder) if you want me to.

VanceKInGa commented 1 year ago

@anthonyreilly, I cannot create a branch. So I am attaching my changes for QueryBuilder.

NetCoreForce.zip

VanceKInGa commented 1 year ago

@anthonyreilly Made a small tweak to make creating the query easier. Should be the last update. NetCoreForce.zip

anthonyreilly commented 1 year ago

@VanceKInGa Thanks, I'll get this merged in

VanceKInGa commented 1 year ago

@anthonyreilly Awesome! I've been working with this for a couple of weeks and added a few ctors to simplify the code. It's pretty tight and powerful now.

NetCoreForce.zip