Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取已筛选子集合的实体_C#_Entity Framework_Linq - Fatal编程技术网

C# 获取已筛选子集合的实体

C# 获取已筛选子集合的实体,c#,entity-framework,linq,C#,Entity Framework,Linq,我有一个实体的立场,有良好的清单 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

我有一个实体的立场,有良好的清单

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; }
}
位置
{
公共int id{get;set;}
//其他属性
公共虚拟ICollection Good{get;set;}
}
好的
{
公共int id{get;set;}
公共字符串名称{get;set;}
public int positionId{get;set;}
公共虚拟位置位置{get;set;}
}
如果我有:
位置1
好的1,name=“A”
好的2,name=“A”
好的3,name=“B”

位置2
好的1,name=“A”
好的2,name=“D”

位置3
好的1,name=“C”
好的2,name=“D”

并使用name=“A”搜索货物,它必须返回
位置1
好的1,name=“A”
好的2,name=“A”
位置2
好的1,name=“A”

换言之,将实体放置在仅包含筛选好的对象的列表中。
我如何通过最少的数据库访问和最少的记录加载来实现这一点?欢迎提供任何提示

在不了解数据库结构的情况下,这似乎是一个可以通过简单连接解决的问题:

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

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

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

(其中“A”应替换为参数)

干得好!我看到您使用适当的实体框架方法来建模位置和良好状态之间的一对多关系。每个位置都有零个或多个商品,每个商品都只属于一个位置

我唯一的建议是在你的资本化(PositionId而不是PositionId)中保持一致,并正确使用复数:一个头寸有零个或多个商品(不是:一个头寸有零个或多个商品)。一致地使用它可以更容易地读取查询,从而增强可维护性。此外,使用适当的大小写和多元化可以最大限度地减少对属性和流畅API的需求

因此,你需要所有位置的序列,其中至少有一个商品的名称等于“A”,以及所有有这个名称的商品

我的经验是,一旦我在实体框架中正确地建模了一对多关系,我就很少再使用连接了。我认为在集合中,从其他集合(有商品的位置)中有零个或多个项目,或者集合是其他元素的一部分(属于某个位置的商品)。实体框架将此转换为联接

你的问题是:

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());
换句话说:从位置集合中的每个位置创建一个具有多个属性的新()对象:

  • 从该位置获取所需的属性。在您的示例中,这类似于“位置1”
  • 来自该位置且名称为“a”的所有货物的顺序
从生成的集合中,仅保留至少有一个
良好的
元素

实体框架将知道这是使用SQL连接/where/select完成的

注释后添加:不带匿名对象的查询

在上面的示例中,我创建了匿名类,因为如果不需要完整的对象,这是最简单、最有效的方法。SQL只会对您请求的属性进行选择

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

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

查询中的Select将略有不同:

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());
类特殊位置
{
公共整数Id{set;set;}
公共字符串名称{get;set}
公共ICollection货物{get;set;
}
类特殊食品
{
公共整数Id{set;set;}
公共字符串名称{get;set}
}
IEnumerable结果=myDbContext.Positions
.选择(位置=>new SpecialPosition()
{
Id=位置。Id,
名称=位置。名称,
货物=位置。货物
.Select(good=>newspecialgood()
{
Id=good.Id,
Name=good.Name,
}
.Where(speicalGood=>specialGood.Name==“A”),
})
//只保留那些至少有一个好的
.Where(element=>element.Goods.Any());

试一试如果你不创建特殊位置和特殊商品,但创建位置和商品,会发生什么情况

你说“位置3好1,name=“A”在你的示例中,没有名称为“A”的“位置3”".我猜你是指位置2?@thomas,没错。更新。谢谢,在SQL中,我可以通过一个非常简单的连接来实现这一点。问题是要编写一个合适的LINQ查询。我有这个,这会给出一个完整的商品列表。我需要它筛选。非常感谢你的详细答案。有没有办法不使用g匿名类型?如果有很多属性,是否有一种快速映射属性的方法?我希望看到一个答案,即只要源代码是原始的
IQueryable
,大多数LINQ语句都会正确地转换为SQL。但是,我想指出,值得研究它使用的命令执行SQL Server profiler或其他类似工具。原因是,如果您研究它,您将看到结果实际上是“扁平化”的(显然,因为它毕竟是一个关系模型)换言之,如果实体A有两个实体B,并且您一起查询该结构,那么发生的情况是……对于参与关系的每个实体B,都会有一行,与实体A请求的列一起-再次-对于每个实体B。这通常不是什么大问题,但如果有多个实体B或实体A的某些列可能很大(长注释等),这可能会导致性能问题