NewEntity() only does this:It creates the object instance (new T()), and then adds the new entity to the object context and passes it back.
publicvirtual TEntity NewEntity()
{
Entity = new TEntity();
Entity = Context.Set<TEntity>().Add(Entity) as TEntity;
OnNewEntity(Entity);
if (Entity == null)returnnull;return Entity;
}
In order for the entity to save it has to be added to the context so I'm not sure what you could possibly be doing different with just new Quote(); DbSet.Add(quote); unless you're not calling DbSet.Add() in which case the new entity won't get added on Save()/SubmitChanges().
If your constructor of the order creates a new Customer object then that customer is treated like a new customer when added to the context, because it's not a tracked entity. IOW, you have to be very careful when you create a new entity in the constructor of related objects. Generally this is a bad idea - only pre-create child collections (because they are empty by default).
But if this was the case you'd still have the same problem with plain entities without calling NewEntity(). Something else is different here.
+++ Rick ---
I'm clearing out the PK on the new Quote before calling Save().
That's not the issue...
The problem is the way the related *CUSTOMER* object is being handled. It's trying to create a new CUSTOMER record also, but the Customer is not new; only the Quote is new and it uses an existing Customer.
You see: QuoteBO.Entity.Customer is an object itslef, and it too gets mapped over from the existing Quote to the new Quote, then Save() is trying to create a new Customer record for it, which is not necessary.
As you can see in my code sample, if I start with "new Quote();" it works fine (this error doesn't happen), but if I start with ".NewEntity()", this error happens.
So, I certainly have a work-around, it's just that I'm wanting to understand what it is about starting with NewEntity() that is causing this issue.
Are you mapping the PK with AutoMapper? If so then yes that would fail.
I don't really understand why you're doing things quite this way. If you have a new Entity you need to create just create a new entity and map the values from the View or DTO or whatever you're mapping from. If you have an existing entity, load the original entity then map to the existing entity in the same way.
Whatever you do with a new entity, don't manually assign the PK to an existing PK or rightfully the insert will fail.
+++ Rick ---
Hi Rick - I'm trying to learn house to make use of NewEntity() in the EF Code First wrapper.... The case I am studying is a common task for may app, where I copy one Quote to a new Quote and edit it from there.
So, I'm using one BO to fetch the existing quote, then I create a new BO instance and use NewEntity(), then I map the existing Quote property values to new Quote entity, and call BO.Save().
However, it is giving an error because it is trying to create a new Customer record also, but it already exists in the table, so it should not be created again.
Here is the code:
public ActionResult test3()
{
var existingQuoteBO = new busQuote(9001); // Loads existing Quote# 9001
var newQuoteBO = new busQuote();
quote newQuote = newQuoteBO.NewEntity();
AutoMapper.Mapper.Map(existingQuoteBO.Entity, newQuote); // Copy existing values to newly created Quote
newQuote.LineItems = new List<quoteitem>(); // Blank out the QuoteLineItems collection that was copied over
newQuoteBO.Save(); <---See error message below.return RedirectToAction("edit", "quotes", new { id = newQuote.id });
}
Here is the error I am getting after calling Save():
Error: Violation of PRIMARY KEY constraint
'PK_customers_1'. Cannot insert duplicate key
inobject'dbo.customers'.
The statement has been terminated.} Westwind.BusinessFramework.EfCodeFirst.EfCodeFirstBusinessBase<MVC4_App1_EFData.Models.quote,MVC4_App1_EFData.QuoteContext> {MVC4_App1_EFData.busQuote}
Surely the EF thing is smart enough not to create a new Customer.???
So, if I skip the NewEntity() technique, and use this approach instead:
var newQuote = new quote();
Then copy the properties from the existing Quote to this new Quote (again using AutoMapper), then I call:
newQuoteBO.Context.Quotes.Add(newQuote);
newQuoteBO.Save()
then it works just fine!!!
So, clearly there is something about using NewEntity() that I am missing.