从 EF 3.1.6 更新到 EF 7.0.7

huangapple go评论55阅读模式
英文:

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&lt;int&gt; 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。

因此,我错误地将问题归因于新库。

对于未来的读者,以下至少有三种更好的处理此情况的方法:

  1. 使用投影到准确的ViewModel,使用.Select(...)
  2. 使用AsNoTracking()
  3. 或者,使用[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:

  1. Use projection to an accurate ViewModel using .Select(...)
  2. Utilize AsNoTracking()
  3. Alternatively, use the [JsonIgnore] attribute.

huangapple
  • 本文由 发表于 2023年6月26日 22:03:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76557422.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定