首页 > 解决方案 > 在 LINQ for EF 中保存具有链接属性的新实体时不创建新实例

问题描述

我注意到,当我存储具有另一种类型的属性的对象时,它会被保存,但链接的属性也是如此。当两者都是新的或都在更新时,这有点整洁。

class Customer
{
  public Guid Id { get; set; }
  public List<Category> Categories { get; set; } ...
}

class Category
{
  public Guid Id { get; set; }
  public string Name { get; set; } ...
}

但是,当我创建一个新的客户实例但链接到一个预先存在的类别时,它变得有点不合适。在这种情况下,类别就像一个标签,所以几个客户将共享一个指向它的指针,每个新客户只需要重用已经存在的类别。(如果类别的 ID 设置为唯一,我会收到已创建对象的错误,如果不是,我会收到重复。)

我知道它与 EF 引擎相关的对象状态有关。它根本不知道新客户中的类别已经存在于数据库中,因此试图创建它。

我玩弄了这个状态并进入了一些复杂的算法,这在某种程度上影响了可读性。然后,我想出了以下方法。我实际上并没有对数据做任何事情——我只是将它拉入 EF 的客户端,让它知道它们的存在。

List<Guid> ids = data.Categories
  .Select(_ => _.Id).ToList();
List<Category> existing = Context.Categories
  .Where(_ => ids.Contains(_.Id)).ToList();

为了简单起见,让我们假设类别的数量是有限的,因此将检索重新编写为下面的代码。(基本上就像在说“嗯……说到类别……好吧,没关系。 ”,这在学术上似乎是错误的。)

List<Categories> _ = Context.Categories.ToList();

在这种情况下,是否有推荐最佳实践的模式或方法?

我意识到上面的示例只是 Q&D 解决方法。提到的实体状态很复杂。我觉得有一种巧妙的方法可以解决它。

标签: c#entity-frameworklinqasp.net-core

解决方案


您不需要将所有现有类别加载到内存中。相反,只需通过从上下文加载新客户与他拥有的现有类别相关联。

Guid[] categoryIdsOfNewCustomer; // passed as part of the create command

var newCustomer = new Customer();
newCustomer.Categories = Context.Categories
    .Where(c => categoryIdsOfNewCustomer.Contains(c.Id))
    .ToList();

Context.Customers.Add(newCustomer);
Context.SaveChanges();

推荐阅读