2012-03-18 55 views
0

小EF问题。 我在EF中映射了多对多关系。 X.Y 所以当我有一个X有一个属性X.Ys.实体框架代码优先 - 多对多过滤

现在我想要做的是使用LINQ查询得到一些X的,但我不希望有所有的Y的选择X的内部。 我想Y's过滤Y.RegistrationDate> Date.Today。

所以,当我有一个X,并通过.Y's,我只会得到未来的Y's。

UPDATE 这工作,导致S中有与它的关系只包含即将举行的活动不同微克的。 但不要告诉我这个不能简化??!

 var t = (from ug in uof.Ugs.All().ToList() 
       from upcomingEvent in ug.Events 
       where upcomingEvent.Date >= DateTime.Today 
       select new 
       { 
        ug, 
        upcomingEvent 
       }).ToList(); 

     var s = (from ug in t.Select(x => x.ug).Distinct() 
       select new UG 
       { 
        Id = ug.Id, 
        Name = ug.Name, 
        Description = ug.Description, 
        WebSite = ug.WebSite, 
        Events = ug.Events.Where(x => x.Date >= DateTime.Today).ToList() 
       }).ToList(); 

UPDATE2

添加的图像显示,即使基本脉络操纵我仍然得到2个事件,事件的时候我拿1!只要你想它

exampledebugimage

回答

2

你有没有试过?:

var query = Xs 
.Select(x => new { x, yCol = x.YCol.Where(y => y.Date >= DateTime.Today) }) 
.AsEnumerable() 
.Select(x => x.x) 
.ToList(); 

参见:http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx

所有这些.ToList使用将意味着你过滤之前,从数据库加载整个表。所以要注意这一点。

UPDATE:作为修正不工作的许多一对多

作为Slauma在评论中提到要确保,如果你要提交变化您不使用这种技术更改跟踪会认为你改变了收藏。或者甚至更好的确保你使用.AsNoTracking(),无论如何它都会提高性能。

我们可以使用与上述相同的解决方案,但对于多对多略有不同。看到这个例子:

[TestClass] 
public class ContextTest 
{ 
    [TestMethod] 
    public void FixupTest() 
    { 
     Database.SetInitializer(new DropCreateDatabaseAlways<Context>()); 

     using (var db = new Context()) 
     { 
      db.Groups.Add(new Group 
      { 
       Name = "G1", 
       Users = new List<User>{ 
        new User{ Name = "M"}, 
        new User{Name = "S"} 
       } 
      }); 

      db.SaveChanges(); 
     } 

     using (var db = new Context()) 
     { 
      var group = db.Groups 
       .Select(g => new { g, Users = g.Users.Where(u => u.Name == "M") }) 
       .AsEnumerable() 
       .Select(g => { 
        g.g.Users = g.Users.ToList(); 
        return g.g; 
       }) 
       .First(); 

      Assert.AreEqual(1, group.Users.Count); 
     } 
    } 


} 



public class User 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public ICollection<Group> Groups { get; set; } 
} 



public class Group 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public ICollection<User> Users { get; set; } 
} 

测试通过而产生的SQL是:

SELECT 
[Project1].[ID] AS [ID], 
[Project1].[Name] AS [Name], 
[Project1].[C1] AS [C1], 
[Project1].[ID1] AS [ID1], 
[Project1].[Name1] AS [Name1] 
FROM (SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent1].[Name] AS [Name], 
    [Join1].[ID] AS [ID1], 
    [Join1].[Name] AS [Name1], 
    CASE WHEN ([Join1].[Group_ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] 
    FROM [dbo].[Groups] AS [Extent1] 
    LEFT OUTER JOIN (SELECT [Extent2].[Group_ID] AS [Group_ID], [Extent3].[ID] AS [ID], [Extent3].[Name] AS [Name] 
     FROM [dbo].[GroupUsers] AS [Extent2] 
     INNER JOIN [dbo].[Users] AS [Extent3] ON [Extent3].[ID] = [Extent2].[User_ID]) AS [Join1] ON ([Extent1].[ID] = [Join1].[Group_ID]) AND (N'Mikael' = [Join1].[Name]) 
) AS [Project1] 
ORDER BY [Project1].[ID] ASC, [Project1].[C1] ASC 
+0

嘿迈克,因为它是多对多的,没有做ToList()并且等待查询结束,会导致错误。这是因为多对多的循环引用。但我会尝试你的选择,看看这是否仍然有效。 – Depechie 2012-03-18 20:29:19

+0

就像我想的那样,错误:“已经有一个与此命令关联的打开DataReader,它必须先关闭”仍然存在!这是y => y.Date ...部分,因为Y也有一个Y.Xs集合! – Depechie 2012-03-18 20:32:30

+0

我认为这是一个连接字符串问题:请看这里http://social.msdn.microsoft.com/Forums/en-MY/adonetefx/thread/8cbe2049-53c9-4c02-b040-18ee30fd7800 – 2012-03-18 20:40:06

3

EF不支持这种情况下,是什么,但是你可以做的是:

var date = DateTime.Date; 
var query = from x in Xs     
      select new 
      { 
       X = x 
       Ys = x.Ys.Where(i = > i.RegistrationDate > date) 
      } 

,这将给你X的集合与他们对应的Y的比赛你那标准。

+0

几乎正确的......但现在我得到几个X的两倍!并且在查询之后添加一个独特的元素并没有帮助...这是因为many2many,所以只有当'found'X还没有出现在结果列表中时才会发生select new。有什么想法吗? – Depechie 2012-03-18 19:40:22

+0

@Depechie和ntziolis:我认为你必须删除从'中的Y x.Ys'线和替换''通过y' i'。 – Slauma 2012-03-18 21:56:21

+0

@Slauma Thx,简单的复制和粘贴错误,它现在已经修复 – ntziolis 2012-03-19 15:24:31