0

I consume a OData-Service with the WCF OData client. In my application when an entity is created, a linked property is set by default to an object:

var defaultPackage = _service.GetDefaultPackage();
var newCar = new Car
{
    Key = "Unique identifier",
    Package = defaultPackage,
    Name = _name
};
_odata.AddToEntity(newCar);
_odata.SetLink(newCar, nameof(Car.Package), newCar.Package);

Then the user can change the values of the car via an user interface. Changes of non primitive properties of instance are autransmitted to the service context. This is done automatically via the INotifyPropertyChanged interface of the car (This interface is automatically implemented for all entities by the odata code generator).

private void PropertyChanged(object sender, PropertyChangedEventArgs e)
{ 
    var car = (Car)sender;
    var newValue = GetPropertyValueByReflection(car, e.PropertyName);
    _odata.SetLink(car, e.PropertyName, newValue);
}

Among other things the user can delete the package of the car. So the property Package gets the value null.

The problem with the solution is now, that the service context does not reset the link for Package, but transfers it at _odata.SaveChanges(SaveChangesOptions.Batch) to the server. This is the batch request:

--batch_0abebbdc-969a-475a-b1da-a94a1733c6ae
Content-Type: multipart/mixed; boundary=changeset_3e2db159-7696-44af-bb51-00d2f48ed944

--changeset_3e2db159-7696-44af-bb51-00d2f48ed944
Content-Type: application/http
Content-Transfer-Encoding: binary

POST http://some-url.to/odata/Cars/Car HTTP/1.1
Content-ID: 5
Content-Type: application/atom+xml
DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 3.0;NetFx
Accept: application/atom+xml,application/xml
Accept-Charset: UTF-8
User-Agent: Microsoft ADO.NET Data Services

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <id />
    <title />
    <updated>2017-06-21T10:58:55Z</updated>
    <author>
        <name />
    </author>
    <content type="application/xml">
        <m:properties>
            <d:Key>Unique identifier</d:Key>
            <d:Name>VW Caddy</d:Name>
        </m:properties>
    </content>
</entry>
--changeset_3e2db159-7696-44af-bb51-00d2f48ed944
Content-Type: application/http
Content-Transfer-Encoding: binary

DELETE $5/$links/Package HTTP/1.1
Content-ID: 10
DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 3.0;NetFx
Accept: application/atom+xml,application/xml
Accept-Charset: UTF-8
User-Agent: Microsoft ADO.NET Data Services

--changeset_3e2db159-7696-44af-bb51-00d2f48ed944--
--batch_0abebbdc-969a-475a-b1da-a94a1733c6ae--

The server answers with an errer, because there is no link to be deleted. Does anybody know a solution for this problem as it is described here to use SetLink(source, propertyName, null) to remove the link.

scher
  • 1,813
  • 2
  • 18
  • 39

1 Answers1

0

Finally I found a solution that now works for me. If the entity is new and there is a link set, SetLink(source, propertyName, null) cannot be used. Instead of that DetachLink(source, propertyName, oldTarget) must be used. I achieve this in the following way:

private void PropertyChanged(object sender, PropertyChangedEventArgs e)
{ 
    var car = (Car)sender;
    var newValue = GetPropertyValueByReflection(car, e.PropertyName);
    object existingTarget;
    if ((newValue == null) && IsAdded(car) &&
         ThereExistsAnExistingLink(car, e.PropertyName, out existingTarget))
        _odata.DetachLink(car, e.PropertyName, existingTarget);
    else
        _odata.SetLink(car, e.PropertyName, newValue);
}

private bool IsAdded(object entity)
{
    return _odata.GetEntityDescriptor(entity).State.HasFlag(EntityStates.Added);
}

private bool ThereExistsAnExistingLink(object entity, 
                                       string propertyName, 
                                       out object existingTarget)
{
    var linkDescriptor = _context.Links.FirstOrDefault(
                           ld => ld.Source == _source && 
                                 ld.SourceProperty == _sourceProperty &&
                                !ld.HasStates(EntityStates.Detached)
                           );
    if (linkDescriptor != null)
    {
        existingTarget = linkDescriptor.Target;
        return true;
    }
    existingTarget = null;
    return false;
}
scher
  • 1,813
  • 2
  • 18
  • 39