【问题标题】:Entity Framework In Memory Database provider weird behavior内存数据库提供程序中的实体框架奇怪的行为
【发布时间】:2021-03-22 13:03:06
【问题描述】:
[HttpGet]
public JsonResult GetTodoItems()
{
    return new JsonResult(_context.TodoItems.ToList());
}

[HttpPost]
public JsonResult PostTodoItem(TodoItem item)
{
    _context.TodoItems.Add(item);
    _context.SaveChanges();
    return new JsonResult("Added successfully!");
}

[HttpDelete("{id}")]
public JsonResult DeleteTodoItem(long id)
{
    _context.TodoItems.Remove(_context.TodoItems.Find(id));
    _context.SaveChanges();
    return new JsonResult("Deleted successfully!");
}

另外,这里是 TodoItem 模型:

public class TodoItem
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
}

由于某种原因,我不明白以下场景的幕后情况:

我使用 API 删除了其中一项。如果我现在将另一个项目添加到列表中,TodoItems 的顺序似乎发生了变化,并且想知道在幕后发生了什么来调用这种行为。

这是一个例子 - 这是开始的情况:

[
    { "Id": 1, "Name": "Item1", "IsComplete": false },    
    { "Id": 2, "Name": "Item2", "IsComplete": false },
    { "Id": 3, "Name": "Item3", "IsComplete": false }
]

现在我删除 Item2 然后 API 返回的列表是:

[
    { "Id": 1, "Name": "Item1", "IsComplete": false },
    { "Id": 3, "Name": "Item3", "IsComplete": false}
]

然后我添加 Item4 然后列表是:

[
    { "Id": 1, "Name": "Item1", "IsComplete": false },
    { "Id": 4, "Name": "Item4", "IsComplete": false },
    { "Id": 3, "Name": "Item3", "IsComplete": false }
]

如您所见,Item4 被添加到最后删除的项目所在的位置。在此之后,如果我添加后续项目,它会继续在列表末尾添加项目并返回。我猜这可能是因为 EF 的 InMemory Database Provider,因为它主要用于测试目的。但即便如此,我还是想知道这个现象背后的列表是如何运作的。

使用本地监视窗口没有帮助,因为它确实从列表中删除了 Item2 对象,并且显然移动了列表以添加新项目。

编辑:当我在这里谈论列表如何工作时,我的意思是 DbSet 在此添加和删除操作中的工作方式,因为 _context.TodoItems 是一个 DbSet 对象,而 ToList() 只是将其转换为列表。

【问题讨论】:

  • 这是正常情况。您可以使用 .OrderBy() 使该怪异动作正常进行。但要小心你的相关数据,在你这样做之前三思而后行。如果您在删除相关数据时决定您的 efcore 将采用哪种方法会更好。如果您遵循代码优先方法learnentityframeworkcore.com/configuration/fluent-api/…,您可以在该链接上查看

标签: c# list entity-framework entity-framework-core in-memory-database


【解决方案1】:

我想知道这个现象背后的列表是如何运作的

每个 EF 提供者都会做这样的事情。 this 返回的项目顺序:

return new JsonResult(_context.TodoItems.ToList());

是存储提供程序的未记录实现细节,如果您希望以任何特定顺序返回项目,则必须在 EF 查询中使用.OrderBy()

如果您对 InMemory 提供程序的实现感到好奇,代码在 GitHub 上,存储是一个

private readonly Dictionary<TKey, object?[]> _rows;

https://github.com/dotnet/efcore/blob/main/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs

这导致:

备注

值的顺序 Dictionary.ValueCollection 未指定,但它是 与中的关联键相同的顺序 由 Keys 属性返回的 Dictionary.KeyCollection。

https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.values?view=net-5.0#remarks

【讨论】:

  • 不是 JsonResult 辅助函数造成了这个问题。肯定是 EF,我从 _context.TodoItems 的值中知道这一点,正如我所提到的,我通过本地监视窗口对其进行了监控。列表移开以在旧项目的位置为新项目创建空间。新元素被添加到列表的末尾,据我所知,这是列表的实现方式。就像我在问题中所说的那样,我想知道这是否是 InMemory 数据库提供程序的问题,或者我是否缺少有关如何在此数据库提供程序背后实现列表的一些信息。
  • 就我的问题的解决方案而言,这是正确的,但我实际上并不是在寻找解决方案。一开始我不会使用 InMemory Database Provider,使用数据库表后列表会很好。
  • 如果数据库以任何特定顺序返回行,这是一个意外,您不应该依赖这种行为。
猜你喜欢
  • 2013-01-08
  • 2010-10-09
  • 2015-09-07
  • 1970-01-01
  • 2017-07-22
  • 2010-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多