Getting an object out of context after adding () before calling SaveChanges ()

Suppose I have a file with several lines, each of which represents Person , and the Person object has an identity column , which is also a primary key . Assuming that a Person could be repeated in a file, if so, maybe I want to run the last scenario of defeating the input. In the example below, I use the repository to retrieve a person from the database by social security number. The problem is that when the same SSN appears again in the file, the repository still returns zero, although technically this person with this SSN has already been added to the context ( SaveChanges has not yet been called). I understand that I can get around this by tracking myself which Person objects have already been added. I am wondering what is the best practice for this scenario. Thanks.

 foreach(row in fileRows) { Person person = personRepository.GetBySSN(row.SSN); if(person == null) { //insert logic } else { //update logic } } personRepository.SaveChanges(); 
+4
source share
4 answers

I have not found anything regarding best practices, so I will post my decision. I know that many other posts relate to the fact that the EF context provides mechanisms to look in it and determine if a particular entity is in a join state. Since I work through repositories (my business layer does not have direct access to the EF context), my choice is either to upload this logic to the repository, or try to solve it at the business level. I feel that this task is really a problem for the business, not the level of data access.

 Dictionary<string, Person> newPeople = ... foreach(row in fileRows) { Person person; //if the person is already tracked by the dictionary, work with it, if not use the repository if(!newPeople.TryGetValue(row.SSN, out person)) { person = personRepository.GetBySSN(row.SSN); } if(person == null) { //insert logic //keep track that this person is already in line for inserting newPeople.Add(row.SSN, person); } else { //update logic } } personRepository.SaveChanges(); 
0
source

I think I can give the same answer that I gave here

To save an object, you usually add it to it with a DbSet in context.

for instance

 var bar = new Bar(); bar.Name = "foo"; var context = new Context(); context.Bars.Add(bar); 

Surprisingly, the context.Bars request cannot be found, only the added object

 var howMany = context.Bars.Count(b => b.Name == "foo"); // howMany == 0 

After context.SaveChanges() 1 will appear 1 the same line

DbSet seems unaware of the changes until they are saved to db.

Fortunately, each DbSet has a Local property that acts like the DbSet itself, but reflects all operations in memory

 var howMany = context.Bars.Local.Count(b => b.Name == "foo"); // howMany == 1 

You can also use Local to add entities.

 context.Bars.Local.Add(bar); 

and get rid of the strange behavior of the Entity Framework.

+8
source

Modify GetBySSN as follows:

 public Person GetBySSN(string ssn) { Person p = context.ObjectStateManager .GetObjectStateEntries(~EntityState.Deleted) .Where(e => !e.IsRelationship) .Select(e => e.Entity) .OfType<Person>() .SingleOrDefault(p => p.SSN = ssn); if (p == null) { p = context.People.SingleOrDefault(p => p.SSN = ssn); } return p; } 
+1
source

If you want to go along the Ladislav route and request an ObjectStateManager, you can use the extension method, for example:

 public static IEnumerable<TEntity> LoadedEntities<TEntity>(this ObjectContext Context) { return Context.ObjectStateManager .GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Unchanged) .Where(e => !e.IsRelationship).Select(e => e.Entity).OfType<TEntity>(); } 

This will allow you to do something like this:

 Person p = context.LoadedEntities<Person>().SingleOrDefault(p => p.SSN = ssn); if (p != null) return p; return context.People.SingleOrDefault(p => p.SSN = ssn); 
0
source

All Articles