我有三个表,我正在使用User,Application,ApplicationAdministrator。 ApplicationAdministrator是一个映射表,用于将User与Application链接,该映射表具有多对多关系。当我尝试以管理员身份添加用户时保存新应用程序时出现以下错误:
无法定义两个对象之间的关系,因为它们附加到不同的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 :(得分:1)
如果您使用两种不同的上下文,则必须将实体与第一种实体分离,并将其附加到要执行更改的第二种实体。您还必须正确配置其状态。要在DbContext API中分离实体,您需要调用:
context.Entry(entity).State = EntityState.Detached;
如果使用相同的上下文加载所有实体并保存其更改,则无需更改其状态。它由变更跟踪自动完成。
顺便说一下。你应该在没有存储库的情况下开始,一旦了解了EF的工作原理以及存储库如何帮助你,就开始使用存储库。
答案 1 :(得分: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);