获取已过滤子集合的实体

时间:2017-08-22 05:45:16

标签: c# entity-framework linq

我有一个具有Good

列表的实体Position
Position
{
public int id { get; set; }
//other properties
public virtual ICollection<Good> Good { get; set; }
}

Good
{
public int id { get; set; }
public string name { get; set; }
public int positionId { get; set; }    
public virtual Position Position { get; set; }
}

所以如果我有:
位置1  好1,名字=&#34; A&#34;
 好2,名字=&#34; A&#34;
 好3,名字=&#34; B&#34;

位置2
好1,名字=&#34; A&#34;
 好2,名字=&#34; D&#34;

位置3
好1,名字=&#34; C&#34;
 好2,名字=&#34; D&#34;

使用姓名=&#34; A&#34;搜索Good,必须返回
位置1  好1,名字=&#34; A&#34;
 好2,名字=&#34; A&#34;
位置2
好1,名字=&#34; A&#34;

换句话说 - 将列表中的实体定位为仅包含已过滤的商品。 如何通过最少的数据库访问和最小的记录加载来实现这一目标?欢迎任何提示

3 个答案:

答案 0 :(得分:1)

干得好!我看到你使用正确的Entity Framework方法来模拟Positions和Good之间的一对多关系。每个职位都有零个或多个商品,每个商品都属于一个职位。

我要给出的唯一建议是在大写中保持一致(PositionId而不是positionId)并正确使用复数形式:一个位置有零个或多个商品(不是:一个位置有零个更好)。一致使用可以更轻松地阅读查询,从而提高可维护性。除了使用适当的大写和复数之外,还最大限度地减少了对Attributes和Fluent API的需求。

所以你想要所有至少有一个Good with Name等于“A”的Position的序列,以及所有具有此名称的商品。

我体验到,一旦我在实体框架中正确地建模了一对多关系,我就不再使用连接了。我认为在其他集合(具有商品的职位)中有零个或多个项目的集合中,或者属于其他元素(属于某个职位的商品)的集合。实体框架会将其转换为连接。

您的查询将是:

var result = myDbContext.Positions.Select(position => new                  
    {
        ... // use the Position properties you want in your result for example:
        Id = position.Id,
        // from the collection of goods, take only the goods with name equals "A":
        Goods = position.Goods.Where(good => good.Name == "A"),
    })
    // keep only those items that have at least one Good
    .Where(element => element.Goods.Any());

在单词中:从位置集合中的每个位置创建一个具有多个属性的新(anonymous type)对象:

  • 您想要的位置属性。在你的例子中,这就像“Position1”
  • 此职位的所有商品的序列,其名称为“A”

从结果集合中仅保留至少有一个Good的元素。

实体框架将知道这是使用SQL join / where / select

完成的

评论后添加:没有匿名对象的查询

在上面的例子中,我创建了匿名类,因为如果你不想要完整的对象,这是最简单和最有效的。 SQL只会对您请求的属性执行选择。

可能是匿名对象对你来说不够好。例如,您希望将查询结果传递给其他函数,或者您希望将结果存放在具有“方法”和其他“属性”的对象中。在这种情况下,您可以创建一个包含结果的特殊类。

请注意,SQL不知道您的特殊类,因此您只能使用没有构造函数的类。

查询中的选择会略有不同:

class SpecialPosition
{
     public int Id {set; set;}
     public string Name {get; set}
     public ICollection<SpecialGood> Goods {get; set;
}
class SpecialGood
{
     public int Id {set; set;}
     public string Name {get; set}
}
IEnumerable<SpecialPosition> result = myDbContext.Positions
    .Select(position => new SpecialPosition()                 
    {
        Id = position.Id,
        Name = position.Name,
        Goods = position.Goods
            .Select(good => new SpecialGood()
            {
                Id = good.Id,
                Name = good.Name,
            }
            .Where(speicalGood => specialGood.Name == "A"),
    })
    // keep only those items that have at least one Good
    .Where(element => element.Goods.Any());

尝试自己如果不创建SpecialPositions和SpecialGoods会发生什么,但是位置和商品

答案 1 :(得分:0)

在不知道您的数据库结构的情况下,这似乎是一个可以通过简单的加入来完成的问题:https://www.w3schools.com/sql/sql_join_left.asp

或者您可以尝试使用linq GroupBy来解决问题:

allPositions.SelectMany(p => p.Good)
.Where(g => g.name == "A")
.GroupBy(g => g.Position)
.ToDictionary(x => x.Key,x => x.ToList());

答案 2 :(得分:0)

这个怎么样?

list.Where(p => p.Good.Any(g => g.Name.Equals("A", StringComparison.OrdinalIgnoreCase)))

(其中&#34; A&#34;应该用参数替换)

相关问题