30

In this simple example, I have two entities: Event and Address. I have a console application running every night to import event data from an XML source and add it to my database.

As I loop through the XML event nodes (inside of the Entity Framework context), I check to see if there is an address record with the given values already in the database. If not, it adds a new record.

using (DemoContext context = new DemoContext())
{
    foreach (XmlNode eventNode in eventsXml.SelectNodes("/Events/Event"))
    {
        Event newEvent = new Event();

        newEvent.Title = **get from XML**

        Address address = context.Addresses.Where(a =>
            a.Title.Equals(title, StringComparison.OrdinalIgnoreCase) &&
            a.Address1.Equals(address1, StringComparison.OrdinalIgnoreCase) &&
            a.Address2.Equals(address2, StringComparison.OrdinalIgnoreCase) &&
            a.City.Equals(city, StringComparison.OrdinalIgnoreCase) &&
            a.State.Equals(state, StringComparison.OrdinalIgnoreCase) &&
            a.ZipCode.Equals(zipCode, StringComparison.OrdinalIgnoreCase)
        ).FirstOrDefault();

        if (address != null)
            newEvent.Location = address;
        else
        {
            newEvent.Location.Title = title;
            newEvent.Location.Address1 = address1;
            newEvent.Location.Address2 = address2;
            newEvent.Location.City = city;
            newEvent.Location.State = state;
            newEvent.Location.ZipCode = zipCode;
        }

        context.Events.Add(newEvent);
    }

    context.SaveChanges();
}

I know it is slower performance to call context.SaveChanges() after every event, so I would like to do this all at the end (or do it in batches but that's not relevant to this problem). However, when I query against context.Addresses, it doesn't seem to be aware of any new addresses until after I call context.SaveChanges() so I get duplicate records.

For my purposes it may be okay to save after each record rather than at the end, but I would like to know if there is a good, simple alternative.

JKasper11
  • 772
  • 1
  • 7
  • 21
  • From what I understand context.SaveChanges() will add new records one by one (separate insert for each record) rather than as a bulk operation. In many cases I prefer to do it one by one to spread database load instead of stressing Sql Server with i.e. 1000 inserts at once. Although single context.SaveChanges() may be better if you want all inserts as part of a single transaction. – Mariusz Aug 01 '17 at 09:47

2 Answers2

30

When you query in a way that the database is touched, then the newly added entities in the context are not included in the result. In EF 4.1 you can get them via DbSet<T>.Local

See :

Why do Entity Framework queries not return unsaved entities

And

Entity Framework: Re-finding objects recently added to context

Community
  • 1
  • 1
Alireza
  • 10,237
  • 6
  • 43
  • 59
  • 1
    Thanks, DbSet.Local seems promising. After a quick test that seems to eliminate the problem of duplicates being added in the same batch, but doesn't prevent duplicates if there is already a record saved in the database.Is there anything I can query against to do both or should I simply make a separate query against context.Addresses if context.Addresses.Local doesn't come back with a result? – JKasper11 Sep 19 '13 at 22:07
  • @JKasper11 The only method I know which queries context and then if necessary DB is Find(key). If the the entity with provided key exists in the context it is returned, otherwise the DB is queried to get it. – Alireza Sep 20 '13 at 07:12
  • 2
    its worth noticing that local not only holds added objects but deleted and modified object too.. – Vishal Sharma Sep 22 '13 at 08:02
  • 2
    @vishalsharma, Microsoft Data Developer Center disagree with you. They say deleted entities not included in local collection: http://msdn.microsoft.com/en-us/data/jj592872.aspx. – Eugene Oct 13 '13 at 14:55
1

Query directly against a DbSet will always send a query to the database. There is a good alternative in Entity Framework 5 – DbSet.Local property that let you work with in-memory data (created by yourself or loaded from database).

Look this article: http://msdn.microsoft.com/en-us/data/jj592872.aspx.

Eugene
  • 389
  • 1
  • 7
  • 18