Question

Was trying out some code with the EF "code first" method and ran into a strange problem.

My datacontext:

    public class BookmarkerDataContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>().HasKey(u => u.UserId);
            base.OnModelCreating(modelBuilder);
        }
     }

Where the user object is:

   public class User
    {
        public long UserId { get; set; }
        public ICollection<Tag> Tags { get; set; }
    }

In my code I am doing something fairly simple:

public void UpdateUserTags(User user,ICollection<Tag> taglist)
    {
        user.Tags = new List<Tag>(user.Tags.Union(taglist));
        datacontext.Users.Add(user);
        datacontext.SaveChanges();
    }

The user object I am passing to this function is the result of something like:

datacontext.Users.SingleOrDefault(u => u.UserId==id)

Everytime I call the UpdateUserTags function it seems to create a new Row in the User table instead of updating it. Am I doing something wrong here?

Was it helpful?

Solution

@Donald is correct, you need to Attach to the ObjectContext when making updates.

However, that is only if your entity is detached.

If sounds like you have already retrieved the single entity from the graph:

var user = datacontext.Users.SingleOrDefault(u => u.UserId==id);

Which means you don't need to Attach or get it again. Just do this:

var user = datacontext.Users.SingleOrDefault(u => u.UserId==id);
user.Tags = new List<Tag>(user.Tags.Union(taglist));
context.SaveChanges();

However, i wouldn't recommend replacing the entire Tags collection, add the tags:

user.Tags.Add(someTag);

HTH

OTHER TIPS

I believe you want to Attach your object to the data context, instead of Adding it.

public void UpdateUserTags(User user,ICollection<Tag> taglist)
{
    datacontext.Attach(user);
    user.Tags = new List<Tag>(user.Tags.Union(taglist));
    datacontext.SaveChanges();
}

Once it is attached, then the context becomes aware of the object. Once you save changes, they should be persisted to the database.

Won't this line

datacontext.Users.Add(user);

Always mark the user record as needing to be ADDED to the users table.

I think you have to DETACH the user from the old context and ATTACH it to the new to properly be able to update the record. but I'm no EF wonk so ymmv

This has nothing to do with your particular issue but for lazy loading you're going to want Tags to be marked virtual

public virtual ICollection<Tag> Tags { get; set; }

Also, it looks like you're trying to add new tags for a user (or update their tags) if that is the case then you're going to want to use Attach as Donald suggested

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top