2011-12-08 157 views
6

如果我有一个查询,看起来像这样:实体框架包括凡

var forms = repo.GetForms().Where(f => f.SubForms.Any(sf => sf.Classes.Any(c => c.TermId == termId))); 

从这里就可以看到我的架构如下:

SubForm有很多Class其中有许多Term

我想要什么:

所有SubForms他们Classes在特定Term

现在发生的事情是,我得到的是具有特定Term任何Class所有SubForm。这意味着SubForm回来了全部孩子Class而不仅仅是与Term有关的。

例如,我有2个学期,每个学期有2个班。这个查询在该特定术语中带回4个类而不是2个。

有什么Include('Expression'),我可以用它来说我只想包括所有基于条件的类?或者是我的查询错误?

+0

第一个'Any'应该是'Where',对吧?否则,你的查询只会返回一个'bool',并且说:“是否有任何具有给定termId的类的子类,是或否? – Slauma

+0

@Slauma对不起,这个表达式上还有另外一个关卡,我会编辑它,对不起 –

回答

0

我不知道关系的确切名称,但它应该是沿Include(Where Expression)不存在的

repo.Terms 
    .Include("Classes") 
    .Include("Classes.SubForms") 
    .SingleOrDefault(x => x.TermId = termId); 

// or 

repo.GetSubForms 
    .Include("Classes") 
    .Where(sf => sf.Classes.Where(c => c.TermId == termId)); 
4

线的东西。如果您使用Include的加载方式,您将始终加载所有元素。

通过使用投影可以解决这个问题。基本的想法是,你将选择一个新的匿名类型与你想要的财产和另一个属性与过滤的导航项目。 EF会将这些链接在一起,因此您将伪造一个Include(Where ...)

Check this for an example

+1

Minor nit:'Include(Expression)'确实存在System.Data.Entity.DbExtensions.Include扩展方法,但是有一个完全不同的含义。它用作字符串文字的替代方法:'repo.Terms.Include(term => term.Classes)'。 – hvd

+0

Thnx。我修改了我的答案 –

0

这似乎是一个常见的要求,今年早些时候我很难找到解决方案。我最终使用了下面链接中包含的解决方案(我不确定这是我找到的确切解决方案,但它是相同的想法)。希望这可以帮助!

Filter the "Includes" table on Entity Framework query

   //Found this method to filter our child objects instead of using .include() 
       var Results = (from res in 
            (from u in DataContext.User 
            where u.Type.ToUpper() != "ADMIN" 
            && u.StartDate <= DateTime.Now 
            && (u.EndDate == null || u.EndDate >= DateTime.Now) 
            select new 
            { 
             User = u, 
             Access = u.Access.Where(a => a.StartDate <= DateTime.Now 
                && (a.EndDate == null || a.EndDate >= DateTime.Now)) 
            } 
            ) 
           select res); 

       //The ToArray is neccesary otherwise the Access is not populated in the Users 
       ReturnValue = Results.ToArray().Select(x => x.User).ToList(); 
6

使用此:

var subForms = repo.GetSubForms.Select(sf = new { 
     SubForm = sf, 
     Classes = sf.Classes.Where(c => c.TermId == termId) 
    }).ToList() 
    .Select(t => t.SubForm) 
    .ToList(); 

UPDATE:基于@ Slauma的评论:

如果要加载SubForm s表示他们有任何Class一个TermtermId,你可以从结束开始;像这样:

var subForms = repo.Terms.Where(t => t.Id == termId).Select(t => new { 
     Term = t, 
     Class = t.Class, 
     SubForm = t.Class.SubForm 
    }).ToList() 
    .Select(t => t.SubForm).ToList(); 

或以最简单的方式,你可以在你Term使用Include,请参阅:

var subForms = repo.Terms.Include("Class.SubForm").Where(t => t.Id == termId) 
        .Select(t => t.Class.SubForm).ToList(); 

注:我可以从你的问题明白了,你有关系是这样的:

SubForm has_many Class has_many Term 

但是,您提供的代码显示ar elationship像这样的:

SubForm has_many Class 
Term has_many Class 

如果可以,把有问题的实体,或解释他们的关系更请。谢谢。

+1

您仍然需要'GetSubForms'和'Select'之间的过滤器:'Where(sf => sf.Classes.Any(c => c.TermId == termId))''。否则,您可以从数据库加载* all *子表单,包括具有不匹配termId的类的子表单。 – Slauma

+0

@Slauma好的,我完全不明白这个问题;所以我更新我的答案;谢谢:) –

+1

没错,问题中的第一个“任何”都令人困惑。我刚才在这个问题上写了一条评论,因为我相信他的意思实际上是一个“Where”。 – Slauma

1

你知道我有时候会开始迷失在漂亮的LINQ扩展方法中,试图弄清楚如何热切地加载我想要的东西并诉诸于一个非常简单的“加入”概念。

var result = 
(from f in SubForums 
from c in Classes 
from t in Term 
where t.TermId = 1 
select new { SubForum = f, Class = c, Term = t }).ToList(); 

这是一个使用预定义导航属性的简单连接(因此您不必指定连接条件)。你返回一个你需要的所有东西的匿名类型。这样做的好处是Entity Framework会为你做自动修复,因此如果你愿意,你可以自由地从你的方法中返回SubForum,它将自动包含Class和后续Term引用。