2009-12-14 84 views
2

我试图执行一个非常简单的任务,这是“与数据库中的角色添加用户”。角色已经填充到数据库中,我只是将该角色添加到用户角色集合中,但它一直抛出以下异常:实体框架附加一个持久对象的新对象

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). 

UPDATE:

这是我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())); 
      }   
     } 

如,你可以看到用户和角色正在使用您已经指出的不同上下文。使用单个数据上下文的问题是我无法正确分层应用程序。

+0

这些ASP.NET FormsAuth用户和角色? – 2009-12-14 21:50:57

+0

不只是表用户和角色(自定义表与认证无关)。 – azamsharp 2009-12-14 21:55:29

回答

4

再次更新基于更新的问题

我不同意你“无法正常层中的应用”当您共享存储库之间的上下文。这是一个需要解决的问题,但它绝对是可以解决的。另外,我想你会发现它容易得多比当您尝试使用多个上下文您创建多少的问题解决。

在任何情况下,真的有只有两个,您的问题可能的解决方案:

  1. 手动跟踪其上下文的具体实体连接到,并将其传输(含附加和分离),必要时。
  2. 在存储库实例之间共享上下文。

在我们的ASP.NET MVC应用程序中,逻辑工作单元是单个请求。因此,我们在请求开始时实例化一个ObjectContext,在请求结束时处理它,并在创建它们时将其注入到新的存储库中。版本库实例永远不会超过一个请求。基于新的问题

更新

是否角色库和用户库中的每个有一个(单独)方面?以下是堆栈跟踪中发生了什么:

  1. 您将用户添加到上下文中。
  2. RelationshipManager通过用户并确保任何相关实体也在上下文中。这涉及到,除其他外,设置他们的EntityKey属性。
  3. 假设角色来自不同的上下文(这似乎是这种情况,否则上下文应该检测到该角色已经在上下文中),您应该会看到一个错误,指出您不能添加附加到的实体一个上下文到另一个上下文出于某种原因,你在这里没有看到。但是,这不是一个有效的操作。
  4. 相反,您在分配角色的EntityKey时会出错。

在我看来,一次只使用一个ObjectContext应该是使用EntityFramework的一般规则。只有当你绝对被迫时,你才应该使用多个上下文,根据我的经验,这几乎从不是。同时使用多个ObjectContexts同时使用显着比一次只使用一个ObjectContext更难。

OK,我不知道你映射的细节,但我希望AddRole是沿着线的东西更多:

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

...如果用户 - >角色是..或:

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

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

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

+0

我更新了原帖!有用户表,角色表和UserRoles。角色已预先填充。 UserRoles具有UserId和RoleId。 – azamsharp 2009-12-14 22:09:42

+0

查看最新的回复。 – 2009-12-14 22:27:35

+0

谢谢!我已经更新了我的回复! – azamsharp 2009-12-14 22:33:34