2016-05-22 6 views
0

У меня есть два класса: Vehicle и OwnershipRecord, и ни одна из них не может быть сохранена в базе данных без другой. A Vehicle должен иметь не менее одного OwnershipRecord, а OwnershipRecord должен быть связан с Vehicle. В противном случае это не имеет смысла.Как я могу использовать POST с навигационными свойствами, используя Microsoft.OData.Client и Web Api

Использование генератора кода клиента Api и OData v4 Я не выяснил способ сериализации обоих объектов и их POST. Кажется, мне нужно ПОСТАВИТЬ автомобиль, а затем добавить OwnershipRecord или опубликовать OwnershipRecord, а затем добавить автомобиль, что невозможно.

DataServiceContext.AddObject обеспечивает следующее:

Объект помещается в трекинга множестве DataServiceContext в состоянии Добавлено. DataServiceContext попытается вставить объект по HTTP POST при следующем вызове SaveChanges. Этот метод не добавляет объекты, связанные с указанным объектом, в DataServiceContext. Каждый объект должен быть добавлен через отдельный вызов AddObject.

Метод не проверяет, что набор сущностей указано в службе данных, связанной с DataServiceContext или что добавленный объект имеет требуемые свойства, необходимые для добавления указанного набора сущностей ..

Таким образом, все свойства навигации имеют значение null при передаче. Поэтому, когда я добавляю OwnershipRecord s к новому автомобилю, а затем звоните Container.AddToVehicles(newVehicle), метод POST на VehiclesController отображает ModelState.IsValid как ложное сообщение Vehicle must have an owner!.

Как я могу использовать код клиента для отправки автомобиля с его навигационным свойством и добавить два вместе? Я попытался использовать AddLink и AddRelatedObject на Container, но он не будет работать с относительным URL-адресом, потому что элементы еще не существуют.

public class Vehicle : IValidatableObject 
{ 
    public const string MissingOwnerMessage = "Vehicle must have an owner!"; 

    public Vehicle() 
    { 
     OwnershipRecords = new HashSet<OwnershipRecord>(); 
    } 

    [Key] 
    public int Id { get; set; } 

    public virtual ICollection<OwnershipRecord> OwnershipRecords { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (OwnershipRecords.Count == 0) 
     { 
      yield return new ValidationResult(MissingOwnerMessage); 
     } 
    } 
} 

public class OwnershipRecord : IValidatableObject 
{ 
    public const string MissingOwnerMessage = "Owner is required when creating Ownership-Record!"; 
    public const string MissingVehicleMessage = "Vehicle is required when creating Ownership-Record!"; 

    public OwnershipRecord() 
    { 
     Owners = new HashSet<Entity>(); 
    } 

    [Key] 
    public int Id { get; set; } 

    [Required] 
    public int VehicleId { get; set; } 

    [ForeignKey("VehicleId")] 
    public virtual Vehicle Vehicle { get; set; } 

    public virtual ICollection<Entity> Owners { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (Owners.Count == 0) 
     { 
      yield return new ValidationResult(MissingOwnerMessage); 
     } 

     if (Vehicle == null) 
     { 
      yield return new ValidationResult(MissingVehicleMessage); 
     } 
    } 
} 

Вот мой WebApiConfig.cs и мои ODataControllers.

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     config.EnableEnumPrefixFree(true); 
     config.MapODataServiceRoute("nms", "nms", GetImplicitEdmModel(), new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer)); 

     config.EnsureInitialized(); 
    } 

    private static IEdmModel GetImplicitEdmModel() 
    { 
     ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); 
     builder.EntitySet<Entity>("Entities"); 
     builder.EntitySet<Vehicle>("Vehicles"); 
     builder.EntitySet<OwnershipRecord>("OwnershipRecords"); 

     builder.Namespace = "LocationService"; 

     return builder.GetEdmModel(); 
    } 

[ODataRoutePrefix("OwnershipRecords")] 
public class OwnershipRecordsController : ODataController 
{ 
    private NirvcModelV2 db = new NirvcModelV2(); 

    // GET: odata/OwnershipRecords 
    [EnableQuery] 
    public IQueryable<OwnershipRecord> GetOwnershipRecords() 
    { 
     return db.OwnershipRecords; 
    } 

    // GET: odata/OwnershipRecords(5) 
    [EnableQuery] 
    public SingleResult<OwnershipRecord> GetOwnershipRecord([FromODataUri] int key) 
    { 
     return SingleResult.Create(db.OwnershipRecords.Where(ownershipRecord => ownershipRecord.Id == key)); 
    } 

    // POST: odata/OwnershipRecords 
    public IHttpActionResult Post(OwnershipRecord ownershipRecord) 
    { 
     if (!ModelState.IsValid) 
     { 
      return BadRequest(ModelState); 
     } 

     db.OwnershipRecords.Add(ownershipRecord); 

     return Created(ownershipRecord); 
    } 

    // GET: odata/OwnershipRecords(5)/Vehicle 
    [EnableQuery] 
    public SingleResult<Vehicle> GetVehicle([FromODataUri] int key) 
    { 
     return SingleResult.Create(db.OwnershipRecords.Where(m => m.Id == key).Select(m => m.Vehicle)); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      db.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 

} 

[ODataRoutePrefix("Vehicles")] 
public class VehiclesController : ODataController 
{ 
    private NirvcModelV2 db = new NirvcModelV2(); 

    // GET: odata/Vehicles 
    [EnableQuery(MaxExpansionDepth = 0)] 
    public IQueryable<Vehicle> GetVehicles() 
    { 
     return db.Vehicles; 
    } 

    // GET: odata/Vehicles(5) 
    [EnableQuery(MaxExpansionDepth = 0)] 
    public SingleResult<Vehicle> GetVehicle([FromODataUri] int key) 
    { 
     return SingleResult.Create(db.Vehicles.Where(vehicle => vehicle.Id == key)); 
    } 

    // POST: odata/Vehicles 
    public IHttpActionResult Post(Vehicle vehicle) 
    { 
     if (!ModelState.IsValid) 
     { 
      return BadRequest(ModelState); 
     } 

     db.Vehicles.Add(vehicle); 
     db.SaveChanges(); 

     return Created(vehicle); 
    } 

    // PATCH: odata/Vehicles(5) 
    [AcceptVerbs("PATCH", "MERGE")] 
    public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Vehicle> patch) 
    { 
     Vehicle vehicle = await db.Vehicles.FindAsync(key); 
     if (vehicle == null) 
     { 
      return NotFound(); 
     } 

     patch.Patch(vehicle); 

     try 
     { 
      await db.SaveChangesAsync(); 
     } 
     catch (DbUpdateConcurrencyException) 
     { 
      if (!VehicleExists(key)) 
      { 
       return NotFound(); 
      } 
      else 
      { 
       throw; 
      } 
     } 

     return Updated(vehicle); 
    } 

    // GET: odata/Vehicles(5)/OwnershipRecords 
    [EnableQuery] 
    public IQueryable<OwnershipRecord> GetOwnershipRecords([FromODataUri] int key) 
    { 
     return db.Vehicles.Where(m => m.Id == key).SelectMany(m => m.OwnershipRecords); 
    } 

    [HttpPost] 
    [ODataRoute("({key})/OwnershipRecords")] 
    public async Task<IHttpActionResult> PostOwnershipRecord([FromODataUri] int key, OwnershipRecord ownershipRecord) 
    { 
     if (!ModelState.IsValid) 
     { 
      return BadRequest(ModelState); 
     } 

     db.OwnershipRecords.Add(ownershipRecord); 
     try 
     { 
      await db.SaveChangesAsync(); 
     } 
     catch (DBConcurrencyException) 
     { 
      throw; 
     } 

     return Created(ownershipRecord); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      db.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 

    private bool VehicleExists(int key) 
    { 
     return db.Vehicles.Count(e => e.Id == key) > 0; 
    } 
} 

== == Обновление

В настоящее время, я сериализация полезной нагрузки с JsonConvert и посылающим его самим, используя WebClient. Я удалил с сервера всю логику ModelState. Кажется, что в настоящее время не поддерживается поддержка свойств навигации в клиентском коде. Я не могу полностью понять перехватывать команду batch, потому что кажется, если я могу использовать expand с ГЭТ, я должен быть в состоянии использовать что-то похожее на expand для POST

ответ

0

Использование $ запроса пакетного отправить два поста в том же ревизией.

Обратитесь к этому образцу проекту, как поддерживаются $ пакетной https://github.com/OData/ODataSamples/tree/master/WebApi/v4/ODataBatchSample

+0

Из того, что я пытался с пакетом, он по-прежнему пытается сохранить каждый отдельно. Мне нужен OwnershipRecord, прикрепленный к серверной стороне транспортного средства, поэтому один вызов db.SaveChanges() будет работать –

+0

Вы пытаетесь использовать набор изменений, запрос в том же наборе изменений сохраняется в одном вызове, а каждый запрос и набор изменений в пакетном запросе обрабатывается последовательно по протоколу. Вы можете обратиться к http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part1-protocol/odata-v4.0-errata02-os-part1-protocol-complete. html # _Change_Sets, чтобы увидеть пример запроса. – Vincent

+0

Я думаю, что мой комментарий был неясным, проблема в валидации. Если я использую 'container.SaveChanges (SaveChangesOptions.BatchWithSingleChangeset)', команда отправляет сообщение для транспортного средства, которое потерпит неудачу, и сообщение для OwnershipRecord, которое потерпит неудачу. Мне нужно на стороне сервера, чтобы получить оба объекта, связать их, а затем сервер может успешно вызвать SaveChanges() –

0

Так я понял, чтобы отправить два параметр вместе, я мог бы использовать Action в WebApiConfig.cs

var newVehicleFunction = builder.EntityType<Entity>().Action("AddVehicle").ReturnsFromEntitySet<OwnershipRecord>("OwnershipRecords"); 
     newVehicleFunction.Parameter<Vehicle>("Vehicle"); 
     newVehicleFunction.Parameter<OwnershipRecord>("OwnershipRecord"); 

Контролер

public IHttpActionResult PostVehicle([FromODataUri] int key, ODataActionParameters parameters) 
    { 
     if (!ModelState.IsValid) 
     { 
      return BadRequest(); 
     } 

     Vehicle vehicle = (Vehicle)parameters["Vehicle"]; 
     OwnershipRecord ownRecord = (OwnershipRecord)parameters["OwnershipRecord"]; 

     var owner = db.Entities.Find(key); 
     if (owner == null) 
     { 
      return NotFound(); 
     } 

     ownRecord.Vehicle = vehicle; 
     owner.OwnershipRecords.Add(ownRecord); 

     try 
     { 
      db.SaveChanges(); 
     } 
     catch (DbUpdateException e) 
     { 
      throw; 
     } 

     return Created(ownRecord); 
    } 

Клиент

 if (newVehicle) 
     { 
      nmsContainer.Entities.ByKey(ownerId).AddVehicle(vehicle, ownRecord).GetValue(); 
     } 

 Смежные вопросы

  • Нет связанных вопросов^_^