【问题标题】:Can I delete a single child entity without loading the entire collection?我可以在不加载整个集合的情况下删除单个子实体吗?
【发布时间】:2015-07-25 15:38:49
【问题描述】:

我有 2 节课,如下所示。

他们可以拥有非常大的收藏 - 一个网站可能有 2,000 多个网站页面,反之亦然。

  class WebsitePage 
  {
    public int ID {get;set;}
    public string Title {get;set;}
    public List<Website> Websites {get;set;}
  }

  class Website 
  {
    public int ID {get;set;}
    public string Title {get;set;}
    public List<WebsitePage> WebsitePages {get;set;}
  }

我在从网站中删除网站页面时遇到问题。特别是在从多个网站中删除网站页面时。

例如,我可能有这样的代码:

var pageToRemove = db.WebsitePages.FirstOrDefault();
var websites = db.Websites.Include(i => i.WebsitePages).ToList();
foreach(var website in websites)
{
    website.WebsitePages.Remove(pageToRemove)
}

如果每个网站Include() 2k 页,您可以想象加载第二行需要很长时间。

但是,如果我在获取网站时不Include() 网站页面,则没有加载子集合供我删除。

我试图只Include() 我需要删除的页面,但当然在保存时会给我一个空集合。

是否有推荐或更好的方法来解决这个问题?

我正在使用现有的 MVC 站点,除非绝对必要,否则我宁愿不必create an entity class for the join table

【问题讨论】:

  • 您是否尝试过直接从 WebSitePages 对象中删除它?

标签: asp.net-mvc collections linq-to-entities


【解决方案1】:

不,你不能……正常地。

只能通过在嵌套集合中添加/删除项目来影响多对多关系(带有隐藏的联结表)。为此,必须加载集合。

但是有一些选择。

选项 1。

通过原始 SQL 从联结表中删除数据。基本上这看起来像

context.Database.ExecuteSqlCommand(
    "DELETE FROM WebsiteWebsitePage WHERE WebsiteID = x AND WebsitePageID = y"));

(不使用参数)。

选项 2。

在类模型中包含联结,即将联结表映射到类WebsiteWebsitePageWebsiteWebsitePage 现在都将拥有

public ICollection<WebsiteWebsitePage> WebsiteWebsitePages { get; set; }

WebsiteWebsitePage 将具有对WebsiteWebsitePage 的引用属性。现在您可以直接通过类模型来操作连接。

我认为这是最好的选择,因为一切都是以标准方式处理具有验证和跟踪等的实体。此外,您迟早会需要一个显式的联结类,因为您需要向其中添加更多数据。

选项 3。

诡计之盒。

我试图通过从集合中删除一个 存根实体 来做到这一点。在您的情况下:创建一个具有有效主键值的 WebsitePage 对象,并将其从 Website.WebsitePages 中删除,而不加载集合。但 EF 没有注意到更改,因为它没有跟踪 Website.WebsitePages,并且该项目一开始不在集合中。

但这让我意识到我必须让 EF 跟踪一个包含 1 个项目的 Website.WebsitePages 集合,然后删除该项目。我首先构建了Website 项目,然后将其附加到一个新的上下文中。我将展示我使用的代码(标准 Product - Category 模型)以防止拼写错误。

Product prd;

// Step 1: build an object with 1 item in its collection
Category cat = new Category { Id = 3 }; // Stub entity
using(var db = new ProdCatContext())
{
    db.Configuration.LazyLoadingEnabled = false;
    prd = db.Products.First();
    prd.Categories.Add(cat);
}

// Step 2: attach to a new context and remove the category.
using(var db = new ProdCatContext())
{
    db.Configuration.LazyLoadingEnabled = false;
    db.Products.Attach(prd);

    prd.Categories.Remove(cat);

    db.SaveChanges(); // Deletes the junction record.
}

延迟加载已禁用,否则在处理prd.Categories 时仍会加载类别。

我对这里发生的情况的解释是:在第二步中,EF 不仅在您附加产品时开始跟踪产品,而且还开始跟踪它的关联,因为它“知道”您不能自己多次加载这些关联很多关系。但是,当您在第一步中添加类别时,它不会这样做。

【讨论】:

  • 谢谢您-非常全面。我不能要求更多,如果可以的话,我会投票两次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-04
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
相关资源
最近更新 更多