正しい親子関係を作成する場合は、挿入されたプレゼンテーション モデル (PM) とエンティティの関係を追跡するだけで済みます。
PM:
public class Parent
{
[Key]
public int? ParentID { get; set; }
[Include]
[Composition]
[Association("Parent_1-*_Child", "ParentID", "ParentID", IsForeignKey = false)]
public IEnumerable<Child> Children { get; set; }
}
public class Child
{
[Key]
public int? ChildID { get; set; }
[Include]
[Association("Parent_1-*_Child", "ParentID", "ParentID", IsForeignKey = true)]
public Parent Parent { get; set; }
}
[Composition] を使用して、WCF RIA が DomainService で InsertChild メソッドを呼び出すようにしてください。
シルバーライト:
...
public Child NewChild(Parent parent)
{
return new Child
{
ParentID = parent.ParentID,
Parent = parent,
};
}
...
public void SubmitChanges()
{
DomainContext.SubmitChanges(SaveComplete, null);
}
...
親が新しくない場合は、ParentID があります。新規の場合、親 ID は null になります。Child.Parent を新しい親の参照に設定することにより、RIA はユーザーが何をしようとしているのかを理解し、参照がサーバーに送信された後も保持されます。
サーバー上の DomainService:
[EnableClientAccess]
public class FamilyDomainService : DomainService
{
private readonly IDictionary<object, EntityObject> _insertedObjectMap;
public void InsertParent(Parent parent)
{
ParentEntity parentEntity = new ParentEntity();
ObjectContext.AddToParents(parentEntity);
_insertedObjectMap[parent] = parentEntity;
ChangeSet.Associate(parent, parentEntity, (p, e) => p.ParentID = e.ParentID;
}
public void InsertChild(Child child)
{
var childEntity = new ChildEntity();
if (child.ParentID.HasValue) // Used when the Parent already exists, but the Child is new
{
childEntity.ParentID = child.ParentID.GetValueOrDefault();
ObjectContext.AddToChildren(childEntity);
}
else // Used when the Parent and Child are inserted on the same request
{
ParentEntity parentEntity;
if (child.Parent != null && _insertedObjectMap.TryGetValue(child.Parent, out parentEntity))
{
parentEntity.Children.Add(childEntity);
ChangeSet.Associate(child, childEntity, (c, e) => c.ParentID = e.Parent.ParentID);
}
else
{
throw new Exception("Unable to insert Child: ParentID is null and the parent Parent cannot be found");
}
}
_insertedObjectMap[child] = childEntity;
ChangeSet.Associate(child, childEntity, (c, e) => c.ChildID = e.ChildID );
}
protected override bool PersistChangeSet()
{
ObjectContext.SaveChanges();
_insertedObjectMap.Clear();
return true;
}
}
ここで重要な 2 つの部分。まず、'_insertedObjectMap' は、ID が設定されていない新しく挿入されたエンティティ間の関係を格納します。これをトランザクションと DB への 1 回の呼び出しで行っているため、ID はすべてのエンティティが挿入された後にのみ設定されます。関係を保存することにより、子 PM はデータベースを使用して親 PM のエンティティ バージョンを見つけることができます。Child エンティティが Parent エンティティの Children コレクションに追加され、LINQToSQL または LINQToEnityFramework が外部キーを処理する必要があります。
2 番目の部分は、トランザクションがコミットされた後に変更を関連付けることです。親と子の両方が送信されるシナリオでは、必ず子に ParentID 外部キーを設定する必要があります。
ChangeSet.Associate() からの私の情報は、http://blogs.msdn.com/deepm/archive/2009/11/20/wcf-ria-services-presentation-model-explained.aspx から来ました。