【发布时间】:2021-12-03 15:08:28
【问题描述】:
由于某种原因,当我从数据库中读取数据并在数据库上下文中创建 SaveChangesAsync() 时,已加载与其关系的实体将从数据库中删除。
Category tools = new("Tools");
ProductType p = new("Hammer", 25, tools);
Ware w1 = new("S1", p, new("Floor"));
Ware w2 = new("S2", p, new("Floor"));
Ware w3 = new("S3", p, new("Floor"));
Ware w4 = new("S4", p, new("Floor"));
Ware w5 = new("S5", p, new("Floor"));
p.AddWare(w1);
p.AddWare(w2);
p.AddWare(w3);
p.AddWare(w4);
p.AddWare(w5);
unitOfWork.ProductTypeRepository.Create(p);
ProductType selected = unitOfWork.ProductTypeRepository.GetByIdAsync(46).Result;
ProductType selected2 = unitOfWork.ProductTypeRepository.GetByIdAsyncWithRelationships(50).Result;
Console.WriteLine("____");
var done = unitOfWork.SaveChangesAsync().Result;
Console.WriteLine(done);
上面的区别是selected中的数据没有被删除,而selected2中的数据是。
两种方法如下
public async Task<ProductType> GetByIdAsync(int id)
{
return await _shopDbContext.ProductTypes.SingleOrDefaultAsync(p => p.ProductTypeId == id);
}
和
public async Task<ProductType> GetByIdAsyncWithRelationships(int id)
{
return await _shopDbContext.ProductTypes
.Include(p => p.OfferProductTypes)
.ThenInclude(op => op.Offer)
.Include(p => p.Wares)
.Include(p => p.Category)
.SingleOrDefaultAsync(p => p.ProductTypeId == id);
}
从我的 MSSQL 数据库服务器分析器中,我可以看到以下内容
exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Ware]
WHERE [WareId] = @p0;
SELECT @@ROWCOUNT;
DELETE FROM [Ware]
WHERE [WareId] = @p1;
SELECT @@ROWCOUNT;
DELETE FROM [Ware]
WHERE [WareId] = @p2;
SELECT @@ROWCOUNT;
DELETE FROM [Ware]
WHERE [WareId] = @p3;
SELECT @@ROWCOUNT;
DELETE FROM [Ware]
WHERE [WareId] = @p4;
SELECT @@ROWCOUNT;
',N'@p0 int,@p1 int,@p2 int,@p3 int,@p4 int',@p0=246,@p1=247,@p2=248,@p3=249,@p4=250
和
exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [ProductTypes]
WHERE [ProductTypeId] = @p5;
SELECT @@ROWCOUNT;
',N'@p5 int',@p5=50
同时我在 UnitOfWork 的 SaveChangesAsync() 中的代码
public Task<int> SaveChangesAsync()
{
var ct = _context.ChangeTracker;
foreach(var e in ct.Entries())
{
Console.WriteLine(e.Entity.GetType().Name + " : " +e.State);
}
return _context.SaveChangesAsync();
}
显示以下内容
____
ProductType : Unchanged
0
它甚至不表示 ProductType 已与其商品和类别一起添加。数据库已更新。
但是,有时它确实会显示更改
ProductType : Added
Category : Added
Ware : Added
Location : Added
Ware : Added
Location : Added
Ware : Added
Location : Added
Ware : Added
Location : Added
Ware : Added
Location : Added
ProductType : Deleted
Ware : Deleted
Ware : Deleted
Ware : Deleted
Ware : Deleted
Ware : Deleted
ProductType : Unchanged
Category : Unchanged
这里是 MCVE 形式的 git 存储库 https://github.com/BenjaminElifLarsen/Shopping---MCVE 的链接。这些文件在 ShoppingCli 中是 program,在 Ipl.Repositories 中是存储库,在 Ipl.Services 中是 UnitOfWork
----- 更新 ----- 我刚刚尝试绕过我的工作单元并直接调用数据库上下文,并且使用 Include() 和 ThenInclude() 与相关实体一起加载的任何实体都将被删除。
【问题讨论】:
-
你能把它变成一个 MCVE 吗?我很高兴尝试在我的机器上运行它,看看我是否可以复制它;这可能是一个应该反馈给 EF 团队的错误。
-
总结我的回答的评论链:我怀疑您的运行时中还有其他线程正在运行导致删除。您显示的最后一个 sn-p 包含 3 条
ProductType消息,并且 EF 上下文只能在给定实体的单个SaveChanges调用中执行一个操作,因此这些ProductType消息不可能引用同一实体相同的上下文和相同的SaveChanges调用了三次。它可能有助于记录更多信息,例如跟踪器中每个实体的 JSON 序列化转储,有助于解释何时引用了哪个实体。 -
@CaiusJard 我会尽快把它变成一个 MCVE,这不是我最有经验的东西,所以可能需要一段时间。
-
@Flater 我将尝试添加更多日志记录。关于其他线程的可能性,应该只有一个线程在运行。
-
你真的必须把它变成minimal reproducible example。您的所有代码都在外部源中。大多数人会忽略您的问题,而且,如果外部来源发生变化,问题将毫无用处。
标签: c# sql-server entity-framework-core