1

I'm using EF6 code first with MVC 5. I have two objects, Movie and User, with each object having a collection of the other (many-to-many). Using an existing User, I'm trying to associate that User to a Movie but no rows are being inserted into the database. The Movie could be existing or new, but either way the association is not being created.

Movie is just a simple POCO

User inherits from IdentityUser

public class User : IdentityUser {

    public virtual ICollection<Movie> Movies { get; set; }

    public User() {
        Movies = new Collection<Movie>();
    }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager) {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}

My Controller Action:

public async Task<HttpResponseMessage> Post(Movie rawMovie) {
    try {
        var movie = _store.Movies.Get(m => m.Id == rawMovie.Id).FirstOrDefault();
        if (movie == null) {
            movie = rawMovie;

            _store.Movies.Insert(movie);
            movie.Cast.Where(n => _store.Cast.Get(e => e.Id == n.Id).Select(e => e.Id).Contains(n.Id))
                .ToList()
                .ForEach(c => _store.Context.Entry(c).State = EntityState.Unchanged);
        }

        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if(user == null) return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid User");
        user.Movies.Add(movie);

        return Request.CreateResponse(_store.SaveChanges());

    } catch (Exception e) {
        return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message);
    }
}

I use the new IdentityDbContext as my single context, so it's used for both authentication and my POCO models - meaning that both Movie and User : IdentityUser share the same the context.

public class ApplicationContext : IdentityDbContext<User> {

    public DbSet<Movie> Movies { get; set; }
    public DbSet<Character> Cast { get; set; }

    public ApplicationContext()
        : base("MoovyConnection", throwIfV1Schema: false) { }

    public static ApplicationContext Create() {
        return new ApplicationContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Movie>().HasMany(m => m.Cast).WithMany(c => c.Movies)
            .Map(t => t.MapLeftKey("Movid_Id").MapRightKey("Character_Id").ToTable("MovieCharacters"));
    }
}

I've found this example but user.Movies does not have an attach method as it is only an ICollection.

What is the proper way to associate two objects to each other in a many-to-many relationship in EF6?

Community
  • 1
  • 1
bflemi3
  • 6,698
  • 20
  • 88
  • 155
  • You should **attach** `user` to the context if it's not an entity tracked by the current context `_store`. – Pragmateek Jul 20 '14 at 12:40
  • I tried that and got the error *An entity object cannot be referenced by multiple instances of IEntityChangeTracker.* So it looks like it's already attached. – bflemi3 Jul 20 '14 at 13:02
  • So before saving, use the `ChangeTracker` API to get the status of the `user` instance: `_store.Entry(user).State` (run a `DetectChanges()` before). It should be `Modified`. – Pragmateek Jul 20 '14 at 14:49
  • @Pragmateek It's not, it's detached, so I attached it and got the same error. – bflemi3 Jul 21 '14 at 01:04
  • Ok, I figured out it's because the UserManager is using a different instance of the context and that's the context the `user` is attached to. The only trouble I'm having now is figuring out how to inject the same context into my `_store`. – bflemi3 Jul 21 '14 at 01:34
  • Look at [this similar question](http://stackoverflow.com/q/22654400/861716). – Gert Arnold Dec 29 '14 at 20:32

0 Answers0