實體框架將持久對象附加到新對象

entity entity-framework

我正在嘗試執行一個非常簡單的任務,即“在數據庫中添加具有角色的用戶”。角色已經填充在數據庫中,我只是將角色添加到用戶角色集合,但它不斷拋出以下異常:

只有當屬性的當前值為null時,才能設置EntityKey屬性。

這是User.cs中的代碼:

  public void AddRole(Role role)
        {
            if (!Exists(role))
            {
                 role.User = this;
                Roles.Add(role);                 
            }
        }

這是測試失敗:

  [Test]        
        public void should_save_user_with_role_successfully() 
        {
            var _role = _roleRepository.GetByName("Student");                        

            _user.AddRole(_role); 

            _userRepository.Save(_user);

            Assert.IsTrue(_user.UserId > 0);             
        }

存儲庫代碼:

  public bool Save(User user)
        {
            bool isSaved = false; 

            using (var db = new EStudyDevDatabaseEntities())
            {   
                db.AddToUsers(user);
                isSaved = db.SaveChanges() > 0;  
            }

            return isSaved; 

        }

這是AddRole方法:

   public bool Exists(Role role)
        {
            var assignedRole = (from r in Roles
                                where r.RoleName.Equals(role.RoleName)
                                select r).SingleOrDefault();

            if (assignedRole != null) return true;

            return false; 
        }

        public void AddRole(Role role)
        {
            if (!Exists(role))
            {
                 role.User = this;
                Roles.Add(role);                 
            }
        }

這是完整的例外:

------ Test started: Assembly: EStudy.Repositories.TestSuite.dll ------

TestCase 'EStudy.Repositories.TestSuite.Repositories.when_saving_new_user.should_save_user_with_role_successfully'
failed: System.InvalidOperationException : The EntityKey property can only be set when the current value of the property is null.
 at System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName, Object complexObject, String complexObjectMemberName, StateManagerTypeMetadata& typeMetadata, String& changingMemberName, Object& changingObject)
 at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName, Object complexObject, String complexObjectMemberName)
 at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)
 at System.Data.Objects.ObjectStateEntry.System.Data.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(String entityMemberName)
 at System.Data.Objects.DataClasses.EntityObject.set_EntityKey(EntityKey value)
 at System.Data.Objects.Internal.LightweightEntityWrapper`1.set_EntityKey(EntityKey value)
 at System.Data.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
 at System.Data.Objects.ObjectContext.AddSingleObject(EntitySet entitySet, IEntityWrapper wrappedEntity, String argumentName)
 at System.Data.Objects.DataClasses.RelatedEnd.AddEntityToObjectStateManager(IEntityWrapper wrappedEntity, Boolean doAttach)
 at System.Data.Objects.DataClasses.RelatedEnd.AddGraphToObjectStateManager(IEntityWrapper wrappedEntity, Boolean relationshipAlreadyExists, Boolean addRelationshipAsUnchanged, Boolean doAttach)
 at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)
 at System.Data.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)
 at System.Data.Objects.DataClasses.RelationshipManager.AddRelatedEntitiesToObjectStateManager(Boolean doAttach)
 at System.Data.Objects.ObjectContext.AddObject(String entitySetName, Object entity)
 C:\Projects\EStudy\EStudySolution\EStudy.BusinessObjects\Entities\EStudyModel.Designer.cs(97,0): at EStudy.BusinessObjects.Entities.EStudyDevDatabaseEntities.AddToUsers(User user)
 C:\Projects\EStudy\EStudySolution\EStudy.BusinessObjects\Repositories\UserRepository.cs(17,0): at EStudy.BusinessObjects.Repositories.UserRepository.Save(User user)
 C:\Projects\EStudy\EStudySolution\EStudy.Repositories.TestSuite\Repositories\Test_UserRepository.cs(47,0): at EStudy.Repositories.TestSuite.Repositories.when_saving_new_user.should_save_user_with_role_successfully()


0 passed, 1 failed, 0 skipped, took 6.07 seconds (NUnit 2.5).

更新:

這是我的UserRepository和RoleRepository,它們都使用不同的上下文:

  public bool Save(User user)
        {
            bool isSaved = false; 

            using (var db = new EStudyDevDatabaseEntities())
            {              
                db.AddToUsers(user);
                isSaved = db.SaveChanges() > 0;  
            }

            return isSaved; 

        }

 public Role GetByName(string roleName)
        {
            using (var db = new EStudyDevDatabaseEntities())
            {
                return db.Roles.SingleOrDefault(x => x.RoleName.ToLower().Equals(roleName.ToLower())); 
            }           
        }

因為,您可以看到用戶和角色正在使用您已經指出的不同上下文。使用單個datacontext的問題是我無法正確分層應用程序。

一般承認的答案

根據更新的問題再次更新

當您在存儲庫之間共享上下文時,我不同意您“無法正確分層應用程序”。這是一個你需要解決的問題,但它肯定是可以解決的。此外,我認為您會發現它比您嘗試使用多個上下文時創建的問題數量要容易得多。

無論如何,您的問題實際上只有兩種可能的解決方案:

  1. 手動跟踪特定實體所附加的上下文,並在必要時傳輸它(使用Attach和Detach)。
  2. 在存儲庫實例之間共享上下文。

在我們的ASP.NET MVC應用程序中,邏輯工作單元是單個Request。因此,我們在請求開始時實例化ObjectContext,在請求結束時將其公開,並在創建它們時將其註入新的存儲庫。存儲庫實例永遠不會超過單個請求。

根據更新的問題更新

角色存儲庫和用戶存儲庫是否都具有(單獨的)上下文?這是堆棧跟踪中發生的事情:

  1. 您將用戶添加到上下文。
  2. RelationshipManager遍歷用戶並確保任何相關實體也在上下文中。除其他外,這涉及設置其EntityKey屬性。
  3. 假設角色來自不同的上下文(似乎是這種情況,因為否則上下文應該檢測到角色已經在上下文中),您應該看到一個錯誤,指示您不能將附加到一個上下文的實體添加到另一個背景。出於某種原因,你在這裡沒有看到。但儘管如此,這不是一個有效的操作。
  4. 相反,在分配角色的EntityKey時會出現錯誤。

在我看來,一次使用一個ObjectContext應該是使用EntityFramework的一般規則。你應該在你絕對被迫的時候使用多個上下文,根據我的經驗,這幾乎從不。多ObjectContexts工作同時比一次處理一個工作顯著困難。

好的,我不知道你的映射的細節,但我希望AddRole是這樣的:

public void AddRole(Role role)
{
    this.Roles.Add(role);
}

...如果User-> Role是..或:

public void AddRole(Role role)
{
    this.Role = role;
}

如果用戶 - >角色是* .. 1。

如果這沒有幫助,請發布異常的堆棧跟踪。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因