英文:
Update from EF 3.1.6 to EF 7.0.7
问题
我最近将 Microsoft.EntityFrameworkCore
包从版本 3.1.6 升级到 7.0.7。
我注意到在使用新包时,每次向名为 Commands
的表中添加新行时,都会执行一个 DELETE
语句,我无法弄清楚为什么。
源代码没有改变。在我呈现大量代码之前,我将向您展示特定的方法和 EF Core 记录器输出。也许有人可以根据这些内容提出想法。
方法
private async Task<int> AddCommandToDatabase(Tracker t, string msg, TrackerCommandType type)
{
await _context.Commands.AddAsync(new Command()
{
CommandType = type,
Timestamp = DateTime.Now,
Message = msg,
TrackerId = t.TrackerId,
CommandDirection = CommandDirection.SENT,
CommandStatus = CommandStatus.OPEN
});
return await _context.SaveChangesAsync();
}
(Tracker 引用来自名为 [Trackers]
而不是 [TrackerConfig]
的表)。
版本 3.1.6 中的包输出:
SET NOCOUNT ON;
INSERT INTO [Commands] ([BatteryLevel], [CommandDirection], [CommandStatus], [CommandType], [Date], [DeviceStatus], [Message], [RollCounter], [StepCounter], [Time], [Timestamp], [TrackerId])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11);
SELECT [CommandId]
FROM [Commands]
WHERE @@ROWCOUNT = 1 AND [CommandId] = SCOPE_IDENTITY();
版本 7.0.7 中的包输出:
SET NOCOUNT ON;
INSERT INTO [Commands] ([BatteryLevel], [CommandDirection], [CommandStatus], [CommandType], [Date], [DeviceStatus], [Message], [RollCounter], [StepCounter], [Time], [Timestamp], [TrackerId])
OUTPUT INSERTED.[CommandId]
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11);
DELETE FROM [TrackerConfig]
OUTPUT 1
WHERE [TrackerConfigId] = @p12;
我会感激任何想法或建议。谢谢。
英文:
I recently updated the Microsoft.EntityFrameworkCore
package from version 3.1.6 to 7.0.7.
I have noticed that with the new package in place, a DELETE
statement is executed every time I add a new row to a table called Commands
, and I cannot figure out why.
The source code has not changed. Before I present a lot of code, I will show you the specific method and the EF Core logger output. Maybe someone has an idea based on that.
Method
private async Task<int> AddCommandToDatabase(Tracker t, string msg, TrackerCommandType type)
{
await _context.Commands.AddAsync(new Command()
{
CommandType = type,
Timestamp = DateTime.Now,
Message = msg,
TrackerId = t.TrackerId,
CommandDirection = CommandDirection.SENT,
CommandStatus = CommandStatus.OPEN
});
return await _context.SaveChangesAsync();
}
(The Tracker reference comes from a table called [Trackers]
not [TrackerConfig]
).
Output for package in version 3.1.6:
SET NOCOUNT ON;
INSERT INTO [Commands] ([BatteryLevel], [CommandDirection], [CommandStatus], [CommandType], [Date], [DeviceStatus], [Message], [RollCounter], [StepCounter], [Time], [Timestamp], [TrackerId])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11);
SELECT [CommandId]
FROM [Commands]
WHERE @@ROWCOUNT = 1 AND [CommandId] = SCOPE_IDENTITY();
Output from package in version 7.0.7:
SET NOCOUNT ON;
INSERT INTO [Commands] ([BatteryLevel], [CommandDirection], [CommandStatus], [CommandType], [Date], [DeviceStatus], [Message], [RollCounter], [StepCounter], [Time], [Timestamp], [TrackerId])
OUTPUT INSERTED.[CommandId]
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11);
DELETE FROM [TrackerConfig]
OUTPUT 1
WHERE [TrackerConfigId] = @p12;
I would appreciate any ideas or suggestions. Thank you.
答案1
得分: 0
感谢Panagiotis Kanavos和Svyatoslav Danyliv,我能够识别出问题所在。原来这是一种反模式。为了便于序列化,我将一个FK(外键)属性(也称为相关实体)设置为null。
当我使用ServiceLifetime.Scoped时,这种行为不是问题,但最近我切换到了ServiceLifetime.Singleton并忘记了它。因此,当我调用SaveChangesAsync时,EF Core会删除实体,但没有必需的FK。
因此,我错误地将问题归因于新库。
对于未来的读者,以下至少有三种更好的处理此情况的方法:
- 使用投影到准确的ViewModel,使用.Select(...)
- 使用AsNoTracking()
- 或者,使用[JsonIgnore]属性。
英文:
Thanks to Panagiotis Kanavos and Svyatoslav Danyliv, I was able to identify the issue. It turned out to be an anti-pattern. To facilitate serialization, I had set an FK (foreign key) property (aka related entity) to null.
This behavior wasn't a problem when using ServiceLifetime.Scoped, but I recently switched to ServiceLifetime.Singleton and forgot it. Consequently, when I call SaveChangesAsync, EF Core deletes the entity without the required FK.
As a result, I mistakenly attributed the issue to the new library.
For future readers, here are at least three better ways to handle this situation:
- Use projection to an accurate ViewModel using .Select(...)
- Utilize AsNoTracking()
- Alternatively, use the [JsonIgnore] attribute.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论