2012-02-18 58 views
2

我想看看我是否可以将3个LINQ查询合并为一个。我遇到的问题是我需要其中一个内部LINQ语句的where子句中的Anon属性之一的值,这似乎不起作用。我也尝试内联LINQ声明,但也没有奏效。使用一种匿名类型的Linq使用其中一种匿名类型属性

有没有人做过这个? PlaceName是我使用PlaceID时遇到的问题。

 var Persons = from _person in people select new 
     { 
      ID = _person.Id, 
      Name = _person.Name, 
      Nationality = _person.Nationality, 
      Age = _person.Age, 
      PlaceID = (from _peopleplaces in peoplePlace where _person.Id ==_peopleplaces.PersonId select _peopleplaces.PlaceId).FirstOrDefault(), 
      PlaceName = (from _places in places where _places.Id == PlaceID select _places.Name).FirstOrDefault() 
     }; 

编辑:我遇到的实际问题是,PlaceID不能在地名查询中使用,它具有其下的红色波浪线。使用1而不是3声明的原因仅仅是为了我自己,我正在学习LINQ并希望看看我能做什么,不能做什么。我假设使用一个集合而不是3个单独的集合来填充Persons对象看起来更好。

实际的错误是PlaceID在当前上下文中不存在。

+1

您有什么麻烦吗? – JaredPar 2012-02-18 22:22:02

+2

为什么不写出不同的3个查询?它的可读性和简单性以及最终结果*最可能*将是相同的,即使在性能方面也是如此。 – Tigran 2012-02-18 22:23:15

回答

0

也许你正在寻找的let关键字?

var Persons = 
    from _person in people 
    let placeID = 
    (
     from _peopleplaces in peoplePlace 
     where _person.Id == _peopleplaces.PersonId 
     select _peopleplaces.PlaceId 
    ).FirstOrDefault() 
    let placeName = 
    (
     from _places in places 
     where _places.Id == placeID 
     select _places.Name 
    ).FirstOrDefault() 
    select new 
    { 
     ID = _person.Id, 
     Name = _person.Name, 
     Nationality = _person.Nationality, 
     Age = _person.Age, 
     PlaceID = placeID, 
     PlaceName = placeName, 
    }; 

编辑:作为@sambomartin正确下文提到的,你需要考虑是否有在peoplePlace为某个人没有进入会发生什么。在上述查询中,这些人仍然返回最终结果,PlaceIDPlaceNamenull

C#允许在intint?之间进行相等比较;如果后者是null,则比较将始终评估为false。因此,当placeIDnull时,来自places的条目将不满足_places.Id == placeID条件(假定Id字段不可空),并且placeName也将评估为null

如果你不想这些人在你的最终结果,你可以通过添加where条款修改您的查询:

var Persons = 
    from _person in people 
    let placeID = 
    (
     from _peopleplaces in peoplePlace 
     where _person.Id == _peopleplaces.PersonId 
     select _peopleplaces.PlaceId 
    ).FirstOrDefault() 
    where placeID != null // ensure that the person has an associated place 
    let placeName = 
    (
     from _places in places 
     where _places.Id == placeID 
     select _places.Name 
    ).FirstOrDefault() 
    where placeName != null // ensure that the place appears in the primary table 
    select new 
    { 
     ID = _person.Id, 
     Name = _person.Name, 
     Nationality = _person.Nationality, 
     Age = _person.Age, 
     PlaceID = placeID, 
     PlaceName = placeName, 
    }; 
+0

我不得不把它交给你,因为这可以实现更多的控制。 – deanvmc 2012-02-18 23:09:41

+0

我很高兴我们帮助你。只需要考虑的一件事是我不确定没有检查,但是如果没有找到记录,FirstOrDefault将返回null。如果placeId在第二个'let'是places.id为空,您可能会得到异常。Id不可为空。 – sambomartin 2012-02-18 23:53:53

+0

@Douglas感谢您的编辑,但它似乎是一个漫长的解决方案,将几个对象合并为一个集合。我通常会使用'let'来防止在查询中多次评估相同的值。我不确定我会如何使用它?这样做有没有好处? – sambomartin 2012-02-19 15:06:17

3

你不能使用PlaceId,直到它被计算出来,即。当它枚举。

没有什么可以阻止你查询单个表达式中的三个对象,例如,

var people = from p in Persons 
      from ppl in PersonPlaces 
      From pl in Places 
      where p.Id == ppl.PersonId 
      && ppl.PlaceId == pl.Id 
      select new { Name=p.Name, PlaceName=pl.Name} 

对不起格式化,在iPad上很难。

H个

山姆

+0

DOH!这几乎是我想做的,但没想到你可以..实用主义呃:) – deanvmc 2012-02-18 22:39:23

+0

是的,或者你可以使用让...当然根据道格拉斯的答案。取决于你需要返回顶部查询。 – sambomartin 2012-02-18 22:48:12