2016-05-22 11 views
0

私は2つのクラスVehicleOwnershipRecordを持っていますが、どちらも他のクラスなしでデータベースに永続化することはできません。 Vehicleには少なくとも1つのOwnershipRecordが必要であり、OwnershipRecordにはVehicleを関連付ける必要があります。そうでなければ意味がない。Microsoft.OData.ClientとWeb Apiを使用してナビゲーションプロパティでPOSTする方法

Web ApiとOData v4クライアントコードジェネレータを使用する私は両方のオブジェクトを直列化して一緒にPOSTする方法を考え出していません。私は車両をPOSTしてからOwnershipRecordを追加するかOwnershipRecordを投稿してからVehicleを追加する必要がありますが、これは不可能です。

DataServiceContext.AddObject次の機能を提供します。

オブジェクトが追加された状態にあるたDataServiceContextの追跡セットに入れています。 DataServiceContextは、次のSaveChangesの呼び出し時にHTTP POSTによってオブジェクトを挿入しようとします。このメソッドは、指定されたエンティティに関連するオブジェクトをDataServiceContextに追加しません。各オブジェクトは、AddObjectを別々に呼び出して追加する必要があります。

方法は全て、したがって..追加の目的は、指定されたエンティティセットに追加するために必要な必要な特性を有すること

を指定されたエンティティセットがたDataServiceContextに関連付けられたデータサービスであることを検証しませんか渡されるとナビゲーションプロパティはnullになります。したがって、OwnershipRecordをnewVehicleに追加してContainer.AddToVehicles(newVehicle)を呼び出すと、VehiclesControllerのPOSTメソッドはModelState.IsValidVehicle must have an owner!という偽と表示します。

クライアントのコードを使用してビークルのナビゲーションプロパティを送信し、2つを一緒に追加するにはどうすればよいですか?私はContainerAddLinkAddRelatedObjectを使用しようとしましたが、アイテムがまだ存在しないため、相対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ロジックをサーバーから削除しました。クライアントコードにNavigation Propertiesを含めることは現在サポートされていないようです。私がGETとexpandを使用することができる場合、私は同じチェンジで2つのポストを送信するためにPOST

答えて

0

使用$バッチリクエストのexpandに似たものを使用することができるはずと思われるので、私は完全に、batchコマンドを傍受理解できないことがあります。

+0

私はバッチで試したことから、まだ個別にそれぞれを保存しようとしています。 db.SaveChanges()への1回の呼び出しが機能するように、Vehicleサーバー側にOwnershipRecordが必要です –

+0

チェンジセットを使用しようとしますか?同じチェンジセット内のリクエストは1回のコールで保存され、各リクエストとチェンジセットはバッチリクエストプロトコルごとに順次処理されます。 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)'を使用すると、失敗するVehicleの投稿とOwnershipRecordの投稿が送信され、失敗します。サーバー側で両方のオブジェクトを受信して​​関連付けると、サーバーはSaveChanges()を正常に呼び出すことができます –

0

https://github.com/OData/ODataSamples/tree/master/WebApi/v4/ODataBatchSampleは、だから私は、私はWebApiConfig.cs

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

コントローラにアクションを使用することができます一緒に2つのパラメータを送信するために実現し、$バッチ​​がサポートされている方法については、このサンプルプロジェクトを参照してください

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(); 
     } 
関連する問題