How to stop a self-tracking object that executes the Add command instead of updating

Sorry in advance for the length of this question!

I have a data structure from which the following Enti data model was created (tables / fields renamed and simplified for ease of understanding!):

Entity Model

The structure of ProductPaymentMethod / ProductPaymentMethod exists, because Customer can have several PaymentMethods , but can choose from them which should be used for Product .

CustomerReference , ProductReference and VendorReference are created based on CustomerId , so they need to be updated after the initial save.

ProductPaymentMethods requires ProductPaymentMethods , so you need to add it after the initial save.

ADO.NET Self-Tracking Entity Generator to generate self ADO.NET Self-Tracking Entity Generator contexts and object classes.

I have a CreateCustomer method in the BLL that generates a new Entity as follows (psuedo-code):

 Customer newCustomer = new Customer() Product newProduct = new Product() Vendor newVendor = new Vendor() List<Currency> newCurrencies = new List<Currency> { new Currency(), new Currency() } List<Frequency> newFrequencies = new List<Frequency> { new Frequency(), new Frequency() } List<PaymentMethod> newPaymentMethods = new List<PaymentMethod> { new PaymentMethod(), new PaymentMethod() } newProduct.Vendors.Add(newVendor) newProduct.Currencies.Add(newCurrencies) newProduct.Frequencies.Add(newFrequencies) newCustomer.Products.Add(newProduct) newCustomer.PaymentMethods.Add(newPaymentMethods) 

newCustomer then passed to the CreateCustomer method in the DAL, which does the following:

 context.Customers.AddObject(customer) context.SaveChanges() return customer 

A return is assigned to the new Customer object in the BLL and the links generated from CustomerId , and added:

 savedCustomer.CustomerReference = generatedCustomerReference savedCustomer.Products.First().ProductReference = generatedProductReference savedCustomer.Products.First().Vendors.First().VendorReference = generatedVendorReference 

The savedCustomer.PaymentMethod collection loops to create a List<ProductPaymentMethod> productPaymentMethods using PaymentMethodIds . Then added:

 savedCustomer.ProductPaymentMethods.Add(productPaymentMethods) 

newCustomer then passed to the UpdateCustomer method in the DAL, which does this:

 context.Customers.ApplyChanges(customer) context.SaveChanges() return customer 

He then returns to the presentation level.

This led to duplication of everything that was created and then updated - I get 2 x Customer , 2 x Product , 2 x Vendor , 4 x PaymentMethod , 4 x Currency and 4 x Frequency entries - UpdateCustomer received the object marked as Added

So, after a little research, I added the following before calling UpdateCustomer :

 savedCustomer.MarkAsModified() savedCustomer.Products.First().MarkAsModified() savedCustomer.Products.First().Vendors.First().MarkAsModified() 

This stopped duplicate Customer , Product and Vendor , but I still got duplicate Currency , Frequency and PaymentMethod records.

The solution I came across was to scroll through each collection and mark each of the names as immutable before calling UpdateCustomer :

 foreach (currency in Customer.Products.First().Currencies) currency.MarkAsUnchanged() 

(repeated for Customer.PaymentMethods and Customer.Products.First().Frequencies )

Now I do not get duplication, and all my data is created.

Finally to my question!

I cannot help but feel that something is missing here. Do I need to check every part of the relationship tree and mark it as Modified or UnChanged (Microsoft has a wonderful mixture of terms!) As necessary before each update?

I thought the term "Self-Tracking" means that all this should be processed automatically.

Is this the right way to use EF / STE or is there a better way?

EDIT: A little more information about my Visual Studio solution.

DAL project - CustomerModel.edmx, CustomerModel.Context.tt and CustomerDAL.cs

Model project - CustomerModel.tt

BLL Project - CustomerBLL.cs

WCF Project - CustomerWCF.svc.cs

CustomerTest.cs Testing Project

CustomerTest.cs uses Private Accessor to call CustomerWCF.svc.cs

CustomerWCF.svc.cs calls CustomerBLL.cs

CustomerBLL.cs calls CustomerDAL.cs

Links DAL Model

BLL DAL and Model Links

Service Links BLL and Model

Test, Service, BLL, and Model Test Links

Should I test ServiceReference instead of PrivateAccessor?

+4
source share
1 answer

EF will execute Add if it considers it to be a new object and update if it considers it to be existing.

If you create an object in code with a new one ... then EF assumes that it is a new object.

If you get an object from the database, change the values ​​and then save, EF knows that it is an existing object and will do the update.

So, if you have an object that was created in the code, but can exist in the database, you must first extract it from the database, update and then save.

+2
source

All Articles