2017-06-21 1 views
0

Je consomme un service OData avec le WCF OData client. Dans ma demande lorsqu'une entité est créée, une propriété liée est définie par défaut à un objet:OData-Client: Comment réinitialiser le lien sur la nouvelle entité

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); 

Ensuite, l'utilisateur peut modifier les valeurs de la voiture via une interface utilisateur. Les changements de propriétés non primitives de l'instance sont amplifiés dans le contexte de service. Cela se fait automatiquement via l'interface INotifyPropertyChanged du car (cette interface est automatiquement implémentée pour toutes les entités par le générateur de code odata).

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

Entre autres choses, l'utilisateur peut supprimer le package de la voiture. Ainsi, la propriété Package obtient la valeur null.

Le problème avec la solution est maintenant, que le contexte de service ne réinitialise pas le lien pour Package, mais le transfère à _odata.SaveChanges(SaveChangesOptions.Batch) au serveur. Ceci est la demande de traitement par lots:

--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-- 

Le serveur répond avec un erreur, car il n'y a pas de lien à supprimer. Quelqu'un sait-il une solution pour ce problème car il est décrit here pour utiliser SetLink(source, propertyName, null) pour supprimer le lien.

Répondre

0

Enfin, j'ai trouvé une solution qui fonctionne maintenant pour moi. Si l'entité est nouvelle et qu'un ensemble de liens est défini, SetLink(source, propertyName, null) ne peut pas être utilisé. Au lieu de cela DetachLink(source, propertyName, oldTarget) doit être utilisé. J'y parviens de la manière suivante:

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; 
}