如何停止自我跟踪实体执行添加而不是更新

发布于 2024-11-08 14:18:41 字数 4114 浏览 0 评论 0原文

提前为这个问题的长度道歉!

我有一个数据结构,从中创建了以下实体数据模型(为了便于理解,表/字段已重命名和简化!):

“Entity

PaymentMethod / ProductPaymentMethod 结构的存在是因为 Customer 可以有多个可用的 PaymentMethods,但可以选择其中每个产品要使用的内容。

CustomerReferenceProductReferenceVendorReference 都是基于 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; ProductPaymentMethods 使用 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()

这停止了重复的 CustomerProductVendor > 但我仍然收到重复的 CurrencyFrequencyPaymentMethod 记录。

我想出的解决方案是在调用 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!):

Entity Model

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只怪假的太真实 2024-11-15 14:18:41

如果 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文