2

LINQ to SQLクラスに加えてプレゼンテーションモデルを使用して、RIAサービスを介してデータを共有しています。Silverlightクライアントで、いくつかの新しいエンティティ(アルバムとアーティスト)を作成し、それらを相互に関連付けました(アルバムをアーティストのアルバムコレクションに追加するか、アルバムにArtistプロパティを設定します-どちらか1つが機能します)。それらをコンテキストに合わせて、変更を送信しました。

サーバー上で、2つの別々のInsert呼び出しを受け取ります。1つはアルバム用、もう1つはアーティスト用です。これらのエンティティは新しいため、ID値は両方ともデフォルトのint値に設定されます(0-私のDBによっては、これがDB内の有効なIDである可能性があることに注意してください)。これは、私が知る限り、IDを設定しないためです。クライアント上の新しいエンティティの場合。アルバム挿入にアーティストが含まれ、アーティスト挿入にアルバムが含まれていても、両方がエンティティであり、L2Sコンテキストがそれらを認識するため、RIAサービスを介してLINQをSQLクラスに転送する場合、これはすべて正常に機能します。ただし、カスタムプレゼンテーションモデルオブジェクトを使用して、それらをLINQ to SQLクラスに変換し直して、プロセス内の関連付けを維持し、L2Sコンテキストに追加できるようにする必要があります。

簡単に言えば、私が知る限り、これは不可能です。各エンティティは独自のInsert呼び出しを取得しますが、IDがないと関連付けが失われるため、1つのエンティティを挿入する方法はありません。データベースがGUID識別子を使用している場合、クライアントでGUID識別子を設定できるため、話は別です。

これは可能ですか、それとも別のデザインを追求する必要がありますか?

4

1 に答える 1

3

正しい親子関係を作成する場合は、挿入されたプレゼンテーション モデル (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 から来ました

于 2010-05-13T22:26:35.823 に答える