2011-05-27 47 views
2

我使用以下RIA Services調用來註冊並返回Project實體。爲什麼實體框架應該在更新時插入?

// On Server; inside RIA Domain Service 
[Invoke] 
public Project CreateNewProject(String a_strKioskNumber) 
{ 
    Decimal dProjectID = ObjectContext.RegisterProjectNumber(a_strKioskNumber) 
         .FirstOrDefault() ?? -1m; 

    // Tried this but it returned zero (0) 
    //int nChanged = ObjectContext.SaveChanges(); 

    var project = (from qProject in ObjectContext.Projects.Include("ProjectItems") 
       where qProject.ID == dProjectID 
       select qProject) 
       .FirstOrDefault(); 

    if (project == null) 
    return null; 

    return project; 
} 

正如你所看到的,它調用了一個返回項目ID的存儲過程。它使用此ID來查找Project實體本身並將其返回。當Project實體返回給客戶端時,它被分離。我將它附加到DomainContext並修改它。

// At Client 
_activeProject = a_invokeOperation.Value; // <-- Detached 
_context.Projects.Attach(_activeProject); // <-- Unmodified 

if (_activeProject != null) 
{ 
    _activeProject.AuthenticationType = "strong"; // <-- Modified 
    _activeProject.OwnerID = customer.ID; 
    _projectItems.Do(pi => _activeProject.ProjectItems.Add(pi)); 
    _activeProject.Status = "calculationrequired"; 
} 

此時它的實體狀態爲Modified。當我提交更改時,它會給我一個有關UNIQUE KEY違例的例外,就好像它試圖插入它而不是更新它。

// At Client 
_context.SubmitChanges(OnProjectSaved, a_callback); 

我對所有操作使用相同的DomainContext實例。爲什麼這不適用?
怎麼回事?這很令人沮喪。

編輯:

我想這(傑夫的建議):

[Invoke] 
public void SaveProject(Project a_project) 
{ 
    var project = (from qProject in ObjectContext.Projects 
       where qProject.ID == a_project.ID 
       select qProject) 
       .FirstOrDefault(); 

    project.SubmitDate = a_project.SubmitDate; 
    project.PurchaseDate = a_project.PurchaseDate; 
    project.MachineDate = a_project.MachineDate; 
    project.Status = a_project.Status; 
    project.AuthenticationType = a_project.AuthenticationType; 
    project.OwnerID = a_project.OwnerID; 
    project.ProjectName = a_project.ProjectName; 
    project.OwnerEmail = a_project.OwnerEmail; 
    project.PricePerPart = a_project.PricePerPart; 
    project.SheetQuantity = a_project.SheetQuantity; 
    project.EdgeLength = a_project.EdgeLength; 
    project.Price = a_project.Price; 
    project.ShipToStoreID = a_project.ShipToStoreID; 
    project.MachiningTime = a_project.MachiningTime; 

    int nChangedItems = ObjectContext.SaveChanges(); 
} 

它沒有絕對沒有。它沒有保存該項目。

+0

「當我提交更改它給了我一個異常」 – BentOnCoding 2011-05-27 20:27:32

+0

你確定的唯一鍵違規正被項目實體造成的?您將添加到活動項目中的項目項目是什麼,它們來自哪裏?我假設錯誤信息告訴你到底是什麼造成的,但我只是想我會確認。 – 2011-05-31 14:35:45

+0

您是否驗證過在客戶端上所做的更改是否包含在服務器調用中?如果他們是,那麼我不知道爲什麼它什麼也沒做。 – 2011-05-31 17:30:53

回答

2

如果您在服務器端添加SaveProject方法並將對象發送回服務器進行保存,會發生什麼情況?

我沒有使用RIA服務完成EF,但我總是將我的對象發送回服務器進行保存。我假設SubmitChanges調用你正在爲你正確地連接所有東西,然後將它發送回服務器,但也許它做了錯誤的事情,手動處理它將修復它。

+0

可能。你的意思是像一個Invoke?我必須嘗試。 – Jordan 2011-05-31 16:58:34

+0

出於某種原因,它迫使我有一個Update方法(它什麼都不做)只是爲了能夠編輯'Project'。我認爲如果我玩了足夠長的時間,它會起作用,但我認爲一個更簡單更清潔的解決方案是使用DTO。即,在客戶端專門使用的單獨對象類型。這樣,它使我能夠更好地控制更新和初始化。最終,因爲我必須手動完成這一切。我一直在反對這種方法,因爲我希望一切都變得更加「無縫」。爲什麼MS讓一切變得如此複雜。 – Jordan 2011-05-31 17:40:16

1

我目前沒有源代碼,但我看到它建議您在Silverlight中爲每個操作使用新的上下文。我今天遇到了類似的問題,這是因爲我使用的服務級別上下文記住了我不想要的以前的值,因此我更改爲爲每個服務調用創建新的上下文,並且行爲成爲我的預期。

public void SaveResponses(ICollection<Responses> items, Action<SubmitOperation> callback) 
     { 
      try 
      { 
       SurveysDomainContext _context = new SurveysDomainContext(); 
       foreach (Responses item in items) 
       { 
        _context.Responses.Add(item); 
       } 

       _context.SubmitChanges(callback, null); 
      } 
      catch (Exception) 
      { 

       throw; 
      } 

     } 
+0

但這是一個單一的操作。這一切都發生在一次。 – Jordan 2011-05-31 12:57:21

+0

但您似乎正在使用全局DataContext。你應該嘗試使用一個新的實例。 – ecathell 2011-05-31 20:34:17

+0

是的,但後來我的所有狀態持有的對象變得分離(並因此無用)。我已經看到它說你應該這樣做,但我不相信。如果RIA服務無法維護狀態,則無效。它不再是一個ORM層;它變成了一個非常複雜的查詢引擎。無用。 – Jordan 2011-05-31 21:08:23

1

至於不能使用單例全局DomainContext的概念,這實際上是有爭議的。在我的項目中,我使用了一個沒有問題的單例DomainContext。在其他項目中,我們爲應用程序中重複使用實體的不同模塊創建了一個新的DomainContext。肯定有優點和缺點。請參閱: Strategies for Handling Your DomainContext (external blog)

+0

是的!我相信DomainContext應該在用例場景中生存下來。當它不再需要或中間使用的情況下,你釋放它並開始一個新的。這就是我對我的應用程序所做的。我把它們放在全局的地方(比如在單例實例中),因爲用例跨越了多個導航頁面。這並不意味着它的靜態和應用程序廣泛。 – Jordan 2011-06-02 15:59:40

0

看來問題是,當您將項目附加到DomainContext時,它會檢查_context.Projects實體集並且未找到具有該主鍵的實體,然後假定新連接的實體並不存在服務器端,提交更改應該插入它。可能的解決方法可能是將新創建的項目顯式加載到DomainContext中。它將確保它在實體上設置正確的狀態 - 也就是說,該項目已經存在於服務器上,並且它是一個更新實例,而不是插入實例。

因此,也許是這樣的:

//after your Project has already been created serverside with the invoke 
_context.Load(_context.SomeQueryThatLoadsYourNewlyCreatedProject(), LoadBehavior.RefreshCurrent, (LoadOperation lo) => { 
    Project project = lo.Entities.FirstOrDefault(); //is attached and has correct state 
    if (project != null) 
    { 
     project.AuthenticationType = "strong"; 
     project.OwnerID = customer.ID; 
     project.Do(pi => _activeProject.ProjectItems.Add(pi)); 
     project.Status = "calculationrequired"; 
     _context.SubmitChanges(); //hopefully will trigger an update, rather than an insert 
    } 
}); 
+0

我試過了,它沒有幫助。當我更新創建的項目時,它仍然嘗試創建一個新的項目。 – Jordan 2011-06-02 16:52:54