Mar*_*nox 3 collections asp.net-mvc linq-to-entities
我有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;}
}
Run Code Online (Sandbox Code Playgroud)
我在从网站上删除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)
}
Run Code Online (Sandbox Code Playgroud)
如果每个网站Include()2k页,你可以想象加载第二行需要很长时间.
但是如果我Include()在获取网站时没有使用WebsitePages,则没有加载子集合供我删除.
我试图只Include()删除我需要删除的页面,但当然保存时会给我一个空集合.
有没有推荐或更好的方法来解决这个问题?
我正在使用现有的MVC站点,除非绝对必要,否则我不想为连接表创建实体类.
不,你不能......通常.
只有通过在嵌套集合中添加/删除项目,才能影响多对多关系(使用隐藏的联结表).为此,必须加载集合.
但是有一些选择.
通过原始SQL从联结表中删除数据.基本上这看起来像
context.Database.ExecuteSqlCommand(
"DELETE FROM WebsiteWebsitePage WHERE WebsiteID = x AND WebsitePageID = y"));
Run Code Online (Sandbox Code Playgroud)
(不使用参数).
将联结包含在类模型中,即将联结表映射到类WebsiteWebsitePage.无论Website和WebsitePage现在有
public ICollection<WebsiteWebsitePage> WebsiteWebsitePages { get; set; }
Run Code Online (Sandbox Code Playgroud)
并且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.
}
Run Code Online (Sandbox Code Playgroud)
延迟加载被禁用,否则在prd.Categories解决时仍会加载类别.
我对此处发生的事情的解释是:在第二步中,EF不仅会在您附加产品时开始跟踪产品,还会跟踪其关联,因为它"知道"您无法在多对多关系中自行加载这些关联.但是,在第一步中添加类别时,它不会执行此操作.
| 归档时间: |
|
| 查看次数: |
296 次 |
| 最近记录: |