From: | Matt Slay |
To: | Rick Strahl |
EF doesn't work if you just 'assign' an entity. Entities have to be created through EF or be attached in some way. IOW, you can't just use the quote object and assign it to Entity and expect that to work.
Using the bus object you can use quoteBO.Attach(quote). With plain EF the dbSet has a similar function with options for setting the change state (which the BO method does automatically).
This should work.
HOWEVER! This is not the right way to do this.
For one thing it's really bad practice to pick up a quote object as a parameter and then post it to the database. What if some robot decides to send you a quote object with a valid id and only one value filled? At that point your entity would actually write out a single property and a bunch of empty property effectively overwriting the entire record in the database. It also means that if you have POST data on a View that every field has to be there! If it's not those missing fields effectively get wiped out.
A better way is to read the values from the quote and assign them - either manually or using something like AutoMapper or WebUtils.FormVarsToObject(). These tools have options to avoid writing missing values into the object. This should ensure that only values that are actually passed are updated, and not the entire entity.
This is something that bugs me around model binding: Rather than being able to update an existing object the object has to be a parameter and get instantiated. While ModelBinding actually does the right thing (reads only POST values), that effect is unfortunately lost when you do it on a newly created instant.
That aside though - Attach() should work.
+++ Rick ---
Rick - I have a basic MVC4 CRUD app up and running, but I cannot figure out how to call the Save() method from the post-back of the Edit action on my controller.
If I understand this EF stuff properly, somehow, I've got to get the Quote entity back into the EfCodeFirst Context, and mark it as "modified" so it will be saved back to the database. I just cannot figure out the right sequence. I've tried to "attach" the Quote entity but that fails for some reason, and when I try calling .Save(quote), it does not give an error, but yet the changes do not get saved.
Here's what I've tried:
[HttpPost]public ActionResult Edit(Quote quote) {try {if (ModelState.IsValid) { var quoteBO = new busQuote();//quoteBO.Attach(quote);//quoteBO.Context.Entry(quote).State = System.Data.EntityState.Modified; quoteBO.Entity = quote; quoteBO.Save(quote);return RedirectToAction("Index"); } return RedirectToAction("Index"); }catch {return View(); } }
The Quote entity is a complex entity, as it has a related Customer object, and a child collection of line items:
Quote entity has:
- various properties from its own table field
- has a Customer object (per PK/FK relationship defined in model attributes)
- has a collection of QuoteItems which are line items on the Quote.
Eventually, I will need to save changes to the QuoteItems collection as well, but for now, I'm just wanting to accomplish saving basic properties on the top Entity in the busQuote object (i.e. the to the Quote table).
Here's the busQuote class:
publicclass busQuote : EfCodeFirstBusinessBase<Quote, QuoteContext> { .... }
Here's the Context:
publicpartialclass QuoteContext: EfCodeFirstContext {public DbSet<Quote> Quotes { get; set; } public DbSet<QquoteItem> QuoteItems { get; set; }public DbSet<Customer> Customers { get; set; }protectedoverridevoid OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new quoteMap()); modelBuilder.Configurations.Add(new quoteitemMap()); modelBuilder.Configurations.Add(new customerMap()); } }