实体框架将持久对象附加到新对象

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。

如果这没有帮助,请发布异常的堆栈跟踪。




许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因