c# - Owned types collection is never updated in EF Core
问题描述
I have an aggregate defined like this:
public class Product {
public int LocalId { get; private set; }
public Something Something { get; private set; }
public ICollection<Price> Prices { get; private set; }
}
public class Something {
public string Name { get; set; }
}
public class Price {
public int Type { get; set; }
public decimal Value { get; set; }
}
And a schema defined like this:
private void DefineProduct(ModelBuilder builder) =>
builder
.Entity<Product>(builder =>
{
builder.HasKey(p => p.LocalId);
builder
.OwnsOne(p => p.Something, smth =>
{
smth.ToTable("somethings");
})
.OwnsMany(p => p.Prices, pp =>
{
pp.ToTable("prices");
});
});
When a price change is requested, I do this (inside the product method not included here for brevity):
Prices.First(p => p.Type == type).Value = newValue;
And then I try to save the product like this:
public async Task UpdateProperties(Product product, IEnumerable<object> props)
{
_context.Attach(product);
_context.Update(product);
foreach (var prop in props)
{
_context.Update(prop);
}
try
{
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
Console.WriteLine("Who the hell allowed such a bug to go into a production release?");
}
}
Now I should mention that the product comes in from an initial query whose results were not tracked (via AsNoTracking()
call), that's why I'm calling the Attach
method in the first line of the method body. The problem is that I'm hitting that catch
statement with an exception message saying:
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions."}
The thing is that I'm not updating the same product anywhere else and that's the only place touching it. Also I use AsNoTracking
as the default. If I comment out the line with _context.Update(prop);
, then there's no exception raised, but the price is not being updated. Also, if I don't update that prices collection but the Something
property, everything goes well. What. The. Hell.
解决方案
拥有类型集合的EF Core 文档明确指出您必须定义拥有的实体 PK(而不是OwnsOne
影子 FK 通常用作 PK)。
因此,您需要定义自己的 PK(就像Id
您所做的那样)或复合 PK - 例如,如果Price.Type
在所有者内部是唯一的,那么您可以使用类似
pp.HasKey("LocalId", "Type");
并避免额外的Id
列。
推荐阅读
- python - Python:在文本文件中,如何根据模式对先前重复的行进行分组?
- react-native - Reg: wdio iOS和Android原生应用程序之间的通用定位器,使用ReactNative开发(除了AccessibilityID)
- python - 需要使用带有 Uplink 的动态参数来扭曲返回分页结果的 API
- spring - 春季启动时延迟初始化获取失败
- php - 如何重写这样的 URL (localhost/mvc/public/index.php?url=watch?v=ohGXBKUkK4c)?
- javascript - React history.push 重新加载组件。希望它只加载一次
- wordpress - 联系表格 7 将图像添加到每个无线电输入
- css - 如何访问后跟 ul 元素的锚标记?
- c# - 使用 Symbola 字体从代码后面写入 Label.Content
- azure - 如何通过 URL 从 Azure Databricks 中的 DBFS 下载