e36M3
e36M3

Reputation: 6022

EF 4.0 Self-Tracking Entities, intended updates are being translated into inserts

Let's assume that the below method lives in a WCF service. The UI retrieved an instance of the Status object, and makes a subsequent call to the service using this method. Instead of assigning the status to the user as I would expect, it attempts to insert the status. What am I doing wrong?

void Method(Status status)
{
    //not sure if this is even needed, the status never changed
    context.Statuses.ApplyChanges(status);

    //get the first user from the database
    User user = context.Users.Where(u => u.Id = 1).First();

    //set user status to some existing status
    user.Status = status;

    //this throws an exception due to EF trying to insert a new entry
    //into the status table, rather than updating the user.StatusId column.
    context.SaveChanges();
}

Upvotes: 0

Views: 718

Answers (3)

eudaimos
eudaimos

Reputation: 675

Have to write an answer because I can't yet comment on another answer (rep score < 50) [something weirdly not right about that, but I get why it's like that] because I wanted to add some clarity to @Ladislav's answer.

The Status object coming in from the WCF call did not come from the same context you are using to find the User object, so the tracking code is not fixed up with that context. This is why attaching it will allow you to save the assignment without the context thinking that status is a new entity requiring an insert into the database.

Upvotes: 0

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364249

The problem is that you are working with attached user. When the STE is attached to the context it behaves exactly in the same way as any other entity. More over its self tracking mechanism is not activated. So you must attach the status to the context before you set it to the user or it will be tracked as a new entity which has to be inserted:

void Method(Status status)
{
    User user = context.Users.Where(u => u.Id = 1).First();

    context.Attach(status);
    user.Status = status;

    context.SaveChanges();
}

Upvotes: 1

BrandonZeider
BrandonZeider

Reputation: 8152

Try this instead:

        using (Entities ctx = new Entities())
        {
            ctx.Statuses.Attach(status);

            ObjectStateEntry entry = ctx.ObjectStateManager.GetObjectStateEntry(status);
            entry.ChangeState(EntityState.Modified);

            //get the first user from the database
            User user = ctx.Users.Where(u => u.Id = 1);

            //set user status to some existing status
            user.StatusID = status.StatusID;

            ctx.SaveChanges();
        }

Here's a tutorial on CRUD with Entity Framework if you're interested.

Upvotes: 1

Related Questions