Matthew Renze
Matthew Renze

Reputation: 642

What is the simplest way to implement an Entity Framework 6 Add-or-Update method

I have a project that uses Entity Framework 6 that does an Add-or-Update (i.e. Upsert) for a bunch of different entity types. For each of these entities, there is an surrogate integer ID (i.e. primary key), a natural key (e.g. customer ID) used for external lookups, and a set of descriptive fields (e.g. Name, Description, etc.)

I have an AddOrUpdate method that does a lookup of the natural key, finds an existing entity in the database, and updates the entity with the new values (if it exists) or creates a new entity and adds it to the database (if it does not already exist).

Here is a sample of the method I came up with (note that "key" is the natural key, not the surrogate ID):

public void AddOrUpdate(int key, string name)
{
    var customer = _database.Customers
        .FirstOrDefault(p => p.Key == key);

    var exists = customer != null;

    if (!exists)
        customer = new Customer();

    customer.Name = name;
    // Update other descriptive fields here

    if (!exists)
        _database.Customers.Add(customer);

    _database.Save();
}

The code works correctly, but it always feels a bit messy. I'm interested in knowing if someone has a better way of solving this problem with Entity Framework that is structurally simpler, reads better, or can be done in less lines of code (without sacrificing readability), and is still easy to unit test.

If so, please post your refactoring of the code above, so that I can learn from your example.

Upvotes: 3

Views: 2735

Answers (1)

Aydin
Aydin

Reputation: 15314

EntityFramework already implements this for you, you can learn more about it here

void Main()
{
    using (AppContext context = new AppContext())
    {
        context.Users.AddOrUpdate(...);
    }
}

public class AppContext : DbContext
{
    public DbSet<User> Users { get; set; }
    
    
}

public class User 
{
    public string UserId { get; set; }
    public string Name { get; set; }
}

EDIT

This answer has been down voted twice because apparently it's not thread safe. This may be a surprise to a few but Entity Framework, as a framework, isn't thread safe.

MSDN DbContext - Thread Safety

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Basically, the thread safety of my solution is irrelevant as any use of Entity Frameworks DbContext (in particular SaveChanges / SaveChangesAsync methods) across parallel threads is going to give you issues as is, out of the box.

Upvotes: 2

Related Questions