如何停止自我跟踪实体执行添加而不是更新
提前为这个问题的长度道歉!
我有一个数据结构,从中创建了以下实体数据模型(为了便于理解,表/字段已重命名和简化!):
PaymentMethod
/ ProductPaymentMethod
结构的存在是因为 Customer
可以有多个可用的 PaymentMethods
,但可以选择其中每个产品
要使用的内容。
CustomerReference
、ProductReference
和 VendorReference
都是基于 CustomerId
生成的,因此必须在初始保存后更新。
ProductPaymentMethods
需要 PaymentMethodIds
,因此必须在初始保存后添加。
已运行ADO.NET 自跟踪实体生成器
来生成自跟踪上下文和对象类。
我在 BLL 中有一个 CreateCustomer
方法,它生成一个新实体,如下(伪代码):
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
然后传递给 CreateCustomer
方法DAL 执行以下操作:
context.Customers.AddObject(customer)
context.SaveChanges()
return customer
返回值分配给 BLL 中的新 Customer
对象以及从 CustomerId
生成的引用并添加:
savedCustomer.CustomerReference = generatedCustomerReference
savedCustomer.Products.First().ProductReference = generatedProductReference
savedCustomer.Products.First().Vendors.First().VendorReference = generatedVendorReference
savedCustomer.PaymentMethod< /code> 集合循环创建
List
使用 PaymentMethodIds
。然后添加:
savedCustomer.ProductPaymentMethods.Add(productPaymentMethods)
newCustomer
然后传递到 DAL 中的 UpdateCustomer
方法,该方法执行以下操作:
context.Customers.ApplyChanges(customer)
context.SaveChanges()
return customer
然后将其返回到表示层
这会导致所有内容都重复创建然后更新 - 我最终会得到 2 x Customer
、2 x Product
、2 x Vendor
、4 x PaymentMethod
、4 x Currency
和 4 x Frequency
记录 - UpdateCustomer
正在接收标记为 Added
的实体
因此,经过一番研究后,我在调用 UpdateCustomer
之前添加了以下内容:
savedCustomer.MarkAsModified()
savedCustomer.Products.First().MarkAsModified()
savedCustomer.Products.First().Vendors.First().MarkAsModified()
这停止了重复的 Customer
、Product
和 Vendor
> 但我仍然收到重复的 Currency
、Frequency
和 PaymentMethod
记录。
我想出的解决方案是在调用 UpdateCustomer
之前循环遍历每个集合并将每个实体标记为未更改:(
foreach (currency in Customer.Products.First().Currencies)
currency.MarkAsUnchanged()
对 Customer.PaymentMethods
和 重复Customer.Products.First().Frequencies
)
我现在没有重复,并且所有数据都已创建。
最后,回答我的问题!
我不禁觉得我在这里错过了一些东西。在每次更新之前,我真的必须检查关系树的每个部分并根据需要标记为“已修改”或“未更改”(Microsoft 的术语很好的混合!)吗?
我认为“自我跟踪”一词意味着所有这些都应该自动处理。
这是使用 EF / STE 的正确方法还是有更好的方法?
编辑:有关我的 Visual Studio 解决方案的更多信息。
DAL 项目 - CustomerModel.edmx、CustomerModel.Context.tt 和 CustomerDAL.cs
模型项目 - CustomerModel.tt
BLL 项目 - CustomerBLL.cs
WCF 项目 - CustomerWCF.svc.cs
测试项目 CustomerTest.cs
CustomerTest.cs 使用 Private Accessor 调用 CustomerWCF.svc.cs
CustomerWCF.svc.cs 调用 CustomerBLL.cs
CustomerBLL.cs 调用 CustomerDAL.cs
DAL 引用 Model
BLL 引用 DAL 和 Model
Service 引用 BLL和模型
测试引用服务、BLL 和模型
我应该针对 ServiceReference 而不是 PrivateAccessor 进行测试吗?
Apologies in advance for the length of this question!
I have a data structure from which the following Enity Data Model has been created (tables/fields renamed and simplified for ease of understanding!):
The PaymentMethod
/ ProductPaymentMethod
structure exists because a Customer
can have multiple PaymentMethods
available but may choose from them which to use per Product
.
The CustomerReference
, ProductReference
and VendorReference
are all generated based on the CustomerId
so must be updated after the initial Save.
The ProductPaymentMethods
need the PaymentMethodIds
so must be added after the initial Save.
The ADO.NET Self-Tracking Entity Generator
has been run to generate the self-tracking context and object classes.
I have a CreateCustomer
method in the BLL which 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
is then passed to CreateCustomer
method in the DAL which does this:
context.Customers.AddObject(customer)
context.SaveChanges()
return customer
The return is assigned to a new Customer
object in the BLL and the references generated from the CustomerId
and added:
savedCustomer.CustomerReference = generatedCustomerReference
savedCustomer.Products.First().ProductReference = generatedProductReference
savedCustomer.Products.First().Vendors.First().VendorReference = generatedVendorReference
The savedCustomer.PaymentMethod
collection is looped through to create List<ProductPaymentMethod> productPaymentMethods
using the PaymentMethodIds
. This is then added:
savedCustomer.ProductPaymentMethods.Add(productPaymentMethods)
newCustomer
is then passed to UpdateCustomer
method in the DAL which does this:
context.Customers.ApplyChanges(customer)
context.SaveChanges()
return customer
This is then returned to the Presentation layer
This resulted in duplicates of everything that had been created and then updated - I'd end up with 2 x Customer
, 2 x Product
, 2 x Vendor
, 4 x PaymentMethod
, 4 x Currency
and 4 x Frequency
records - UpdateCustomer
was receiving an entity marked as Added
So after a bit of research I added the following before calling UpdateCustomer
:
savedCustomer.MarkAsModified()
savedCustomer.Products.First().MarkAsModified()
savedCustomer.Products.First().Vendors.First().MarkAsModified()
This stopped the duplicated Customer
, Product
and Vendor
but I was still getting duplicated Currency
, Frequency
and PaymentMethod
records.
The solution I came up with was to loop through each of the collections and mark each of the entites as unchanged before calling UpdateCustomer
:
foreach (currency in Customer.Products.First().Currencies)
currency.MarkAsUnchanged()
(repeated for Customer.PaymentMethods
and Customer.Products.First().Frequencies
)
I now get no duplication and all my data is created.
Finally, on to my question!
I can't help but feel that I am missing something here. Do I really have to check each part of the relationship tree and mark as Modified or UnChanged (nice mixture of terms there Microsoft!) as necessary before each and every update?
I thought the term 'Self-Tracking' meant that all that should be handled automatically.
Is this the correct way to use EF / STE or is there a better way?
EDIT: A little more info regarding 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
Test project CustomerTest.cs
CustomerTest.cs uses Private Accessor to call CustomerWCF.svc.cs
CustomerWCF.svc.cs calls CustomerBLL.cs
CustomerBLL.cs calls CustomerDAL.cs
DAL references Model
BLL references DAL and Model
Service references BLL and Model
Test references Service, BLL and Model
Should I be testing against a ServiceReference instead of the PrivateAccessor?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果 EF 认为它是一个新对象,则将执行“添加”;如果认为它是现有对象,则将执行更新。
如果您在代码中使用 new ... 创建一个对象,那么 EF 会假定它是一个新对象。
如果您从数据库获取一个对象,更改值然后进行保存,EF 就会知道它是现有对象并将进行更新。
因此,如果您有一个在代码中创建的对象,但可能存在于数据库中,则必须首先从数据库中检索它,更新它,然后进行保存。
EF will perform a Add if it thinks it is a new object and update if it thinks that it is an existing.
If you create a object in code, with new ... then EF assumes that it is a new object.
If you get an object from the database, change the values and then do a save, EF knows that it is an existing object and will do an update.
So if you have an object that has been created in code, but may exist in the database, you must first retrieve it from the database, update it and then do a save.