My domain model uses EntityFramework 4.1 (and I'm using code-first) to update my DB with linked entities. I have a Member table and then a many-to-many MemberPositions table. The problem is that when I attempt to perform an update on a member with changed permissions, the code throws a run-time error of "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" when I set the following from my repository class:
_context.Entry(entity).State = EntityState.Modified
Now I have read the posts at the following links, but they look outdated and some of the code doesn't work in EF 4.1 / MVC3:
So my questions are:
To help you, below is a stripped down version of my domain model:
public class Entity
{
public int Id { get; set; }
}
public class Member : Entity
{
public string Name { get; set; }
public virtual List<MemberPosition> Positions { get; set; }
}
public class MemberPosition : Entity
{
public string Name { get; set; }
}
public class EfDbContext : DbContext
{
public DbSet<Member> Members { get; set; }
public DbSet<MemberPosition> MemberPositions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new MemberMap());
modelBuilder.Configurations.Add(new MemberPositionMap());
}
}
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
ToTable("Members");
HasMany(m => m.Positions).WithMany().Map(
m => m.ToTable("Member_MemberPositions").MapLeftKey("MemberId").MapRightKey("PositionId"));
}
}
public class MemberPositionMap : EntityTypeConfiguration<MemberPosition>
{
public MemberPositionMap()
{
ToTable("MemberPositions");
Property(x => x.Name).IsRequired().HasMaxLength(100);
}
}
public interface IRepository<TEntity>
{
bool Update(TEntity entity);
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : Entity
{
private readonly EfDbContext _context;
private readonly DbSet<TEntity> _dbSet;
public Repository(EfDbContext context)
{
_context = context;
_dbSet = _context.Set<TEntity>();
}
public bool Update(TEntity entity)
{
_context.Entry(entity).State = EntityState.Modified;
_context.SaveChanges();
return true;
}
}
And, finally, a stripped down version of the Edit method in my MemberController:
public class MemberController : Controller
{
[HttpPost]
public ActionResult Edit(MemberDetailViewModel memberDetailViewModel)
{
if (ModelState.IsValid)
{
var updatedMember = // Gets the member data from the view model...
var memberRepository = // Creates a Repository<Member>;
memberRepository.Update(updatedMember);
return // blah... blah... blah...
}
}
}
Any suggestions are appreciated!
EDIT: THIS IS THE SOLUTION (IT'S EASY!)
In the App_Start.NinjectMVC3 controller, use the following code (make sure that InRequestScope) is present. In my original code, it wasn't, hence it wasn't working...
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
}
As Slauma stated (and as included in my original post as an edit), here's the solution.
In the App_Start.NinjectMVC3 controller, use the following code (make sure that InRequestScope) is present. In my original code, it wasn't, hence it wasn't working...
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
}