1

I have a Model, We can call Person

// My table tb_person
public class Person
{
   public int Id {get;set;}
   public string Name {get; set;}
   public int Age {get; set;}
   public DateTime AddTime {get; set;}
   public DateTime UPdateTime {get;set;}
   public string Remark {get; set}
   public bool IsEnable {get;set;}
}

First I get the Mdoel

using (var ctx = new MyEntitys())
{
  ctx.Configuration.ProxyCreationEnabled = false;
  ctx.Configuration.LazyLoadingEnabled = false;

  Person firstModel = ctx.Persons.Where( x=> x.Id = 5).FirstOrDefault();
}

Now long time after I need to modify the Model, But I need to get the old model in Database and compare something.

using (var ctx = new MyEntitys())
{
  ctx.Configuration.ProxyCreationEnabled = false;
  ctx.Configuration.LazyLoadingEnabled = false;

  Person CurrentModel = ctx.Persons.Where( x=> x.Id = 5).FirstOrDefault();
   // Just a example for judge or compare
   if (CurrentModel.IsEnable)
   {
       if (CurrentModel.UpdateTime != null)
      {
         firstModel.Update = time;
      }
   }
   else
    {
        firstModel.AddTime = new DateTime();
    }
     ctx.Entry(firstModel).State = System.Data.Entity.EntityState.Modified;
     ctx.SaveChanges();
}

Then It will throw:

Why don't I use CurrentModel to update ? Because firstModel I change so many property, I don't want to copy all property. I just need to get some info from Database, and replace it then Save.


I already see this:An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key

That way I don't like it. I get confused, and It's Complicated.

I also use trying to another way to fixed it:

// just judge it without get it

if (ctx.Persons.Any( x=> x.Id = 5 && x.UpdateTime != null){
  // then do something change after judge
}

Basicly now I know the problem source it : Entity Framework cache the result after get it . That's why after I get a new model, It don't let me use the old.

But I still searching a better and height performance way(I just want less deals with Database) to fix it. Do you have any idea?

Community
  • 1
  • 1
qakmak
  • 1,287
  • 9
  • 31
  • 62

1 Answers1

1

When you get the entry for an object using Entry(), context checks if there is an entry for that object reference in the context then returns it, and if there is no entry for that object reference, it adds an entry for that object to the context.

When you create var p1= new Person() and var p2=new Person(), then p1 and p2 are not the same, even if all properties of them are the same, they have different references.

In your case modified entity (first) and original entity are different instances and so context tries to create an entry for first and because you have loaded original version to context an exception of Object with the same key already exists will be thrown.

To know what you can do, Consider this scenarios:

Scenario 1

In this scenario, You get a person from context and pass it to client and then client sends the modified version to you to put in database, and also you want to check the original version of person for something and then update database. You should do it this way:

//get original version
original= context.Persons.Where( x=> x.Id = modified.Id ).FirstOrDefault();
//do comparison and what you want to do
//but only apply changes to modified version
if (original.Age > 20)
    modified.SomeProperty=SomeValue;

//save modified version
context.Entry(original).CurrentValues.SetValues(modified);
context.SaveChanges();

this way is like to ApplyCurrentValues method of ObjectContext in previous versions of Entity Framework

Scenario 2

In this scenario, you get a person from context and pass it to client and then client sends the modified version to you and you (without need of checking for original version) will put it in database.

You should do it this way:

context.Entry(modified).State = EntityState.Modified;
context.SaveChanges();

And there is no need to finding the original.

More info:

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Sorry, I still not understand . The language so official. Can you use some simple way or code explain it? thank you. – qakmak Sep 05 '15 at 18:01
  • Yes, but It is strongly recommended to read the useful link that I put in More info section of Asnwer :) – Reza Aghaei Sep 05 '15 at 18:03
  • Really sorry I already see it. I don't know what is the `tracked entity`. I also can't see that code has any relationship about my code example..... – qakmak Sep 05 '15 at 18:09
  • What application framework you are using? `ASP.Net MVC`, `Windows Forms`? – Reza Aghaei Sep 05 '15 at 18:12
  • There is a Windows service on Server(with ef6.1), and My Winform application get the model from server and send to server after modify. Server will be change it use EF – qakmak Sep 05 '15 at 18:17
  • Ok, I will update the answer and add more description to be useful for other users too:) – Reza Aghaei Sep 05 '15 at 18:19
  • @qakmak I updated the answer for you. I hope you find it useful :) – Reza Aghaei Sep 05 '15 at 19:26
  • Would you mind upvoting the accepted answer? It's not compulsory at all but it's reasonable and recommended :) – Reza Aghaei Jul 06 '16 at 22:44