私は2つのクラスVehicle
とOwnershipRecord
を持っていますが、どちらも他のクラスなしでデータベースに永続化することはできません。 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.IsValid
をVehicle must have an owner!
という偽と表示します。
クライアントのコードを使用してビークルのナビゲーションプロパティを送信し、2つを一緒に追加するにはどうすればよいですか?私はContainer
でAddLink
とAddRelatedObject
を使用しようとしましたが、アイテムがまだ存在しないため、相対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
私はバッチで試したことから、まだ個別にそれぞれを保存しようとしています。 db.SaveChanges()への1回の呼び出しが機能するように、Vehicleサーバー側にOwnershipRecordが必要です –
チェンジセットを使用しようとしますか?同じチェンジセット内のリクエストは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
私のコメントは不明だと思う、問題は検証です。 'container.SaveChanges(SaveChangesOptions.BatchWithSingleChangeset)'を使用すると、失敗するVehicleの投稿とOwnershipRecordの投稿が送信され、失敗します。サーバー側で両方のオブジェクトを受信して関連付けると、サーバーはSaveChanges()を正常に呼び出すことができます –