2011-09-01 52 views
0

我有三个与User,Application,ApplicationAdministrator一起工作的表。 ApplicationAdministrator是一个映射表,用于将用户链接到具有多对多关系的应用程序。我收到以下错误,当我尝试保存掀起了新的应用程序添加了作为管理员的用户:以多对多的关系保存数据

两个对象之间的关系不能被定义,因为它们连接到不同的ObjectContext对象。

所以我的下一步是创建一个BaseRepository,它有一个共同的上下文。不过,现在我得到以下错误,当我尝试修改已经连接到上下文的实体:

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key. 

为什么这是一个艰难的过程?我已经看到了解决方案,连接和重新连接,分离和旋转你的头5次,然后一切都会工作。将实体附加到一个上下文中会根据我附加的上下文来重复其中一个实体。

所有帮助非常感谢!

UserRepository.cs:

public class UserRepository : BaseRepository<User>, IUserRepository 
{ 
    // private ManagerDbContext _context = new ManagerDbContext(); 

    public UserRepository(ManagerDbContext context) 
     : base(context) { } 

    public IQueryable<User> Users 
    { 
     get { return _context.Users.Include("Administrates").Include("Company"); } 
    } 

    public void SaveUser(User user) 
    { 
     _context.Entry(user).State = user.Id == 0 ? EntityState.Added : EntityState.Modified; 

     _context.SaveChanges(); 
    } 

    public void DeleteUser(User user) 
    { 
     _context.Users.Remove(user); 

     _context.SaveChanges(); 
    } 
} 

ApplicationRepository.cs:

public class ApplicationRepository : BaseRepository<Application>, IApplicationRepository 
{ 
    // private ManagerDbContext _context = new ManagerDbContext(); 

    public ApplicationRepository(ManagerDbContext context) 
     : base(context) { } 

    public IQueryable<Application> Applications 
    { 
     get { return _context.Applications.Include("Administrators"); } 
    } 

    public void SaveApplication(Application app) 
    { 
     _context.Entry(app).State = app.Id == 0 ? EntityState.Added : EntityState.Modified; 
     _context.SaveChanges(); 
    } 

    public void DeleteApplication(Application app) 
    { 
     _context.Applications.Remove(app); 
     _context.SaveChanges(); 
    } 
} 

UserConfiguration.cs:

public UserConfiguration() 
{ 
    this.HasKey(x => x.Id); 

    this.Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
    this.Property(x => x.FirstName).IsRequired(); 
    this.Property(x => x.LastName).IsRequired(); 
    this.Property(x => x.Username).IsRequired(); 
    this.Property(x => x.CompanyId).IsRequired(); 

    this.HasRequired(user => user.Company).WithMany().HasForeignKey(user => user.CompanyId); 
    this.HasRequired(user => user.Company).WithMany(company => company.Users).WillCascadeOnDelete(false); 

    this.HasMany(user => user.Administrates) 
     .WithMany(application => application.Administrators) 
     .Map(map => map.MapLeftKey("UserId") 
      .MapRightKey("ApplicationId") 
      .ToTable("ApplicationAdministrators")); 
} 

ApplicationConfiguration.cs:

public ApplicationConfiguration() 
{ 
    this.HasKey(x => x.Id); 

    this.Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
    this.Property(x => x.Name).IsRequired(); 
    this.Property(x => x.Description); 

    this.HasMany(application => application.Administrators) 
     .WithMany(user => user.Administrates) 
     .Map(map => map.MapLeftKey("ApplicationId") 
      .MapRightKey("UserId") 
      .ToTable("ApplicationAdministrators")); 
} 

保存实体的代码片段。

long appId = Int64.Parse(form["ApplicationId"]); 
long userId = Int64.Parse(form["UserId"]); 

Application app = appRepository.Applications.FirstOrDefault(a => a.Id == appId); 
User user = userRepository.Users.FirstOrDefault(u => u.Id == userId); 

app.Administrators.Add(user); 

appRepository.SaveApplication(app); 

return RedirectToAction("Index"); 
+0

http://stackoverflow.com/questions/2666601/why-is-this-exception-the-relationship在这两个对象之间无法定义 – 62071072SP

+0

@ShaliniPavan,这是使用ObjectContext的老派EntityFramework,我想使用DbContext。 DbContext不允许您从其上下文中分离实体。 – bdparrish

回答

0

这是我终于想出来的解决方案。

我创建了一个Func字典,以便在我的上下文中将实体附加到正确的EntitySet。其中一个缺点就是你必须对EntitySet名称进行一些硬编码,所以我在我的POCO中使用了一个静态变量。

BaseRepository.cs

public class BaseRepository<T> where T : class 
{ 
    public static ManagerDbContext baseContext; 

    public BaseRepository() { } 

    public BaseRepository(ManagerDbContext context) 
    { 
     baseContext = context; 
    } 

    private static object _entity; 

    public void AttachEntity(object entity) 
    { 
     _entity = entity; 

     entityAttachFunctions[entity.GetType().BaseType](); 
    } 

    private Dictionary<Type, Func<bool>> entityAttachFunctions = new Dictionary<Type, Func<bool>>() 
    { 
     {typeof(User),() => AttachUser()}, 
     {typeof(Application),() => AttachApplication()} 
    }; 

    private static bool AttachUser() 
    { 
     ((IObjectContextAdapter)baseContext).ObjectContext.AttachTo(User.TableName, _entity); 

     return true; 
    } 

    private static bool AttachApplication() 
    { 
     ((IObjectContextAdapter)baseContext).ObjectContext.AttachTo(Application.TableName, _entity); 

     return true; 
    } 
} 

UserRepository。CS

public void AttachEntity(object entity) 
{ 
    baseContext = _context; 

    base.AttachEntity(entity); 
} 

public void DetachUser(User user) 
{ 
    _context.Entry(user).State = EntityState.Detached; 

    _context.SaveChanges(); 
} 

ApplicationRepository.cs

public void AttachEntity(object entity) 
{ 
    baseContext = _context; 

    base.AttachEntity(entity); 
} 

public void DetachApplication(Application app) 
{ 
    _context.Entry(app).State = EntityState.Detached; 

    _context.SaveChanges(); 
} 

AdminController.cs

long appId = Int64.Parse(form["ApplicationId"]); 
long userId = Int64.Parse(form["UserId"]); 

Application app = appRepository.Applications.FirstOrDefault(a => a.Id == appId); 
User user = userRepository.Users.FirstOrDefault(u => u.Id == userId); 

userRepository.DetachUser(user); 

appRepository.AttachEntity(user); 

app.Administrators.Add(user); 

appRepository.SaveApplication(app); 
1

如果您使用两个不同的上下文中,您必须从第一个分离的实体,将其连接到要进行更改第二个。您还必须正确配置其状态。要分离实体的DbContext API需要调用:

context.Entry(entity).State = EntityState.Detached; 

如果使用相同的上下文加载所有实体和保存他们的更改你不需要改变自己的状态。它通过更改跟踪自动完成。

Btw。您应该在没有存储库的情况下启动,并且一旦了解EF如何工作以及存储库如何帮助您,就开始使用存储库。