我有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;}
}
我在从网站上删除WebsitePage时遇到问题。特别是从mutliple网站删除WebsitePage时。
例如,我可能有这样的代码:
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。
答案 0 :(得分:5)
不,你不能......通常。
多对多关系(使用隐藏的联结表)只能通过添加/删除嵌套集合中的项目来影响。为此,必须加载集合。
但是有一些选择。
通过原始SQL从联结表中删除数据。基本上这看起来像
context.Database.ExecuteSqlCommand(
"DELETE FROM WebsiteWebsitePage WHERE WebsiteID = x AND WebsitePageID = y"));
(不使用参数)。
将联结包含在类模型中,即将联结表映射到类WebsiteWebsitePage
。 Website
和WebsitePage
现在都有
public ICollection<WebsiteWebsitePage> WebsiteWebsitePages { get; set; }
和WebsiteWebsitePage
将具有Website
和WebsitePage
的引用属性。现在,您可以直接通过类模型操作联结。
我认为这是最好的选择,因为一切都采用标准的方式来处理具有验证和跟踪的实体。此外,很可能迟早你需要一个明确的联结类,因为你想要为它添加更多的数据。
一窍门。
我尝试通过从集合中删除存根实体来实现此目的。在您的情况下:创建一个具有有效主键值的WebsitePage
对象,并将其从Website.WebsitePages
中删除,而不加载该集合。但是EF并没有注意到这一变化,因为它没有跟踪Website.WebsitePages
,并且该项目不在集合中。
但这让我意识到我必须让EF跟踪一个Website.WebsitePages
集合,其中包含1个项目,然后删除该项目。我通过首先构建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不仅会在您附加产品时开始跟踪产品,还会跟踪产品的关联,因为它知道&#39;你不能在多对多的关系中自己加载这些关联。但是,当您在第一步中添加类别时,它不会这样做。