2010-01-30 33 views
2

我使用LINQ to SQL類上的演示模型通過RIA服務共享數據。在Silverlight客戶端上,我創建了一些新實體(專輯和藝術家),並將它們相互關聯(將專輯添加到藝術家的專輯集合中,或者將相冊中的藝術家屬性設置爲任意一個),添加他們的上下文,並提交更改。RIA服務:插入多個演示文稿模型對象

在服務器上,我得到兩個單獨的插入調用 - 一個用於專輯,另一個用於藝術家。這些實體是新的,所以它們的ID值都被設置爲默認的int值(0-請記住,根據我的DB,這可能是DB中的有效ID),因爲據我所知,您不設置ID用於客戶端上的新實體。如果我通過RIA服務傳輸LINQ to SQL類,這一切都可以正常工作,因爲即使Album插入包含Artist,而Artist插入包含Album,但實體和L2S上下文都可以識別它們。但是,使用我的自定義表示模型對象,我需要將它們轉換回LINQ to SQL類,以維護進程中的關聯,以便將它們添加到L2S上下文中。

簡而言之,據我所知,這是不可能的。每個實體都有它自己的插入調用,但是沒有辦法插入這個實體,因爲沒有標識,這些關聯就會丟失。如果數據庫使用了GUID標識符,這將是一個不同的故事,因爲我可以在客戶端上設置它們。

這是可能的,還是我應該追求另一種設計?

回答

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; } 
} 

請務必使用[組合]強制WCF RIA調用DomainService上的InsertChild方法。

的Silverlight:

... 
public Child NewChild(Parent parent) 
{ 
    return new Child 
       { 
        ParentID = parent.ParentID, 
        Parent = parent, 
       }; 
} 
... 
public void SubmitChanges() 
{ 
    DomainContext.SubmitChanges(SaveComplete, null); 
} 
... 

如果家長是不是新的,它有一個PARENTID。如果它是新的,則父ID將爲空。通過將Child.Parent設置爲新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; 
    } 
} 

兩個重要的部分在這裏。首先,'_insertedObjectMap'存儲新插入的沒有設置ID的實體之間的關係。由於您在交易和單個DB調用中執行此操作,因此只會在插入所有實體後才設置ID。通過存儲關係,Child PM可以使用數據庫找到Parent PM的實體版本。 Child實體被添加到Parent實體的Children集合中,LINQToSQL或LINQToEnityFramework應該爲您處理外鍵。

第二部分是在事務提交後關聯更改。在提交父項和子項的情況下,您必須記得在子項上設置ParentID外鍵。

我從ChangeSet.Associate()信息是從哪裏來的:http://blogs.msdn.com/deepm/archive/2009/11/20/wcf-ria-services-presentation-model-explained.aspx

+0

這就是答案,據我所知道的,所以謝謝你的張貼。我想我在研究這件事時偶然發現了一些類似的東西,但我認爲問題在於,實際上我正在處理的是比單純的父母/子女關係更復雜的對象圖,我不認爲這是一種解決方案將會擴展以處理這種複雜性。 – nlawalker 2010-05-17 16:14:34