2

I'm new to EF, and I'm trying to understand the best way to handle inserting and updating data. Just for some context, I'm using the .net mvc website boiler plate, and I've created a customers table with a 1:1 relationship to aspnetusers. I've created a view to manage customer data.

Here is my HttpPost ActionResult:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> AddCard(External.Stripe.Customer customer)
    {
        if (!ModelState.IsValid)
        {
            return View(customer);
        }

        External.Stripe.CustomerOperations co = new External.Stripe.CustomerOperations();
        customer = co.Create(customer);

        var user = UserManager.FindById(User.Identity.GetUserId());
        customer.UserId = user.Id;

        var context = new External.Stripe.CustomerContext();


        context.Customers.Add(customer);
        context.SaveChanges();

        return RedirectToAction("Index", "Manage");
    }

I feel like I'm going down the wrong path, because if I make any updates to the customer model, I actually need to check EF if my key already exists, and if it does, run an update instead. I figured EF would have a native way of saving my model if it needs to be updated. I also don't know if this is even where I would persist my model, or if it is better placed somewhere else in my code.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Chris Jenkins
  • 719
  • 7
  • 20
  • 1
    I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders May 13 '15 at 20:43
  • Thanks John, will keep that in mind for the future – Chris Jenkins May 13 '15 at 20:46

2 Answers2

3

Short Answer

...if I make any updates to the customer model, I actually need to check EF if my key already exists, and if it does, run an update instead.

AddOrUpdate() does just this. From the docs:

Adds or updates entities by key when SaveChanges is called. Equivalent to an "upsert" operation from database terminology

Example

In other words, change your code to this:

context.Customers.AddOrUpdate(c => c.UserId, customer);
context.SaveChanges();

In the above example, the c => c.UserId is an expression specifying that the UserId should be used when determining whether an Add or Update operation should be performed.

Considerations

  • AddOrUpdate() matches database tables based on an arbitrary, user supplied key value. In the example, this key is UserId. Be sure to use an appropriate key.
  • AddOrUpdate() updates all entity values and sets database cells to null for properties that a lack value. Be sure to set all the property values of the object (e.g. customer) before using it.

See also

Update Row if it Exists Else Insert Logic with Entity Framework It has a few answers that talk about four or more different approaches.

Community
  • 1
  • 1
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
  • 2
    Isn't `AddOrUpdate` for migrations? – Jacob Roberts May 13 '15 at 21:03
  • It does appear it was primarily designed for migrations, but it is working exactly as expected. My other question is do I even need to write this kind of stuff, or is there a better way to do what I'm trying to do? With simple CRUD actions, this seems like a lot of extra overhead. – Chris Jenkins May 13 '15 at 21:05
  • 1
    Essential reading: Take care with the AddOrUpdate method: http://thedatafarm.com/data-access/take-care-with-ef-4-3-addorupdate-method/ – Colin May 14 '15 at 08:41
2

I personally like a long winded approach of pulling the data object and using if null to determine if it should be added or updated. However, I do have a table with a lot of columns that gets changed frequently due to new or deprecated business rules. So I use the below

var currentModel = dbContext.Table.First(t => t.Id == _id);
dbContext.Entry(currentModel).CurrentValues.SetValues(newModel);
dbContext.SaveChanges();

I get my newModel from my viewModel where I have a ToModel method that returns the DTO. Now all I have to update is my view and viewModel when a change to the database table is made.

Jacob Roberts
  • 1,725
  • 3
  • 16
  • 24
  • Using `dbContext.Table.First(t => t.Id == _id)` to check for existence has the same limitation as the way we check for existence with `AddOrUpdate`. In both cases, it's up to the user to provide an appropriate key value. In your example, you happen to be checking the `Id` value, which is likely a primary key. That's good. It's still *possible* though for a less informed user to use an inappropriate key. – Shaun Luttin May 14 '15 at 16:59