EF6 Linq 查询。仅包括返回子表的第一个条目

Posted

技术标签:

【中文标题】EF6 Linq 查询。仅包括返回子表的第一个条目【英文标题】:EF6 Linq Query .Include only returning first entry of child table 【发布时间】:2017-04-15 06:34:58 【问题描述】:

我想检索给定口袋妖怪的遭遇列表,因为口袋妖怪可以在很多地方遇到,所以我一直在尝试许多变体

var currentPokemon = _context.Pokemon
                                     .Where(mon => mon.Id == id)
                                     .Include(mon => mon.Encounters)
                                     .FirstOrDefault();

结果是一个包含所有相关数据的口袋妖怪对象,但只有第一次遭遇被检索并放入一个集合中,结果如下:

查看数据库,大约有 20 次与毛毛虫的遭遇,我想访问所有这些,但只能获得一个。

Pokemon 类的样子(省略不相关的字段):

[Table("pokemon")]
public partial class Pokemon 
    public Pokemon()
    
        Encounters = new HashSet<Encounters>();
    
    [Column("id")]
    public long Id  get; set; 
    [Required]
    [Column("identifier", TypeName = "VARCHAR(79)")]
    public string Identifier  get; set; 
    .
    .
    .

    [InverseProperty("Pokemon")]
    public virtual ICollection<Encounters> Encounters  get; set; 
 

邂逅是什么样子的:

public partial class Encounters 
    .
    .
    .
    [ForeignKey("PokemonId")]
    [InverseProperty("Encounters")]
    public virtual Pokemon Pokemon  get; set; 

数据库数据:

我在这里误会了什么?

【问题讨论】:

生成的sql是什么?上网看看如何获​​取sql查询 你能显示db的记录吗?你指的是正确的数据库吗? @sampath i.imgur.com/s9N7WyP.png 您指的数据库是否正确? 我无法使用全新的 DbContext 和最少的数据重现此行为。我按预期得到了口袋妖怪和遭遇。您未显示的代码中必须有其他内容。您发布的代码是可以的,并且您执行操作的顺序虽然不是最佳的,但确实会生成相同的 sql。 【参考方案1】:

我想是因为你打电话给.FirstOrDefault(),它只得到第一个项目。你可以省略它并添加.ToList()吗?此外,var currentPokemon 似乎不是一个好的变量名。你说你想要一个遭遇列表,对吧? var pokemonEncounters呢?

【讨论】:

首先或默认将在口袋妖怪结果上完成,而不是遭遇 弗雷杜所说的。省略 .FirstOrDefault() 只会返回一个长度为 1 的口袋妖怪数组,这是没有意义的,因为我只想得到 1 个口袋妖怪。至于我在寻找什么,这是一个单独的口袋妖怪,其中列出了该口袋妖怪的所有相关遭遇。用简单的英语,我想问“谁是 pokemon #10”并得到“Pokemon 10 是 Caterpie,你可以在以下地方找到 Caterpie:(地点列表)。”在最后添加.ToList() 会导致遭遇列表,但没有口袋妖怪。 怎么样 var currentPokemon = _context.Pokemon .Where(mon => mon.Id == id) .Include(mon => mon.Encounters) .FirstOrDefault().Select(p => p .遭遇); 你不能在.FirstOrDefault()返回的口袋妖怪对象上调用.Select() @Fredou 和@Riwen - 你是对的。现在我想起来了,var currentPokemon = _context.Pokemon.Include(mon =&gt; mon.Encounters).FirstOrDefault(p =&gt; p.Id = id); 应该返回第一个带有遭遇列表的口袋妖怪。您应该能够使用currentPokemon.Encounters 访问遭遇。对吗?【参考方案2】:

我认为问题在于您使用 ForeignKey 和 InverseProperty 设置关系的方式。

尝试重写为:

[Table("Pokemon")]
public class Pokemon

    public int Id  get; set; 
    public string Name  get; set; 

    [InverseProperty("Pokemon")]
    public ICollection<Encounter> Encounters  get; set; 



[Table("Enconters")]
public class Encounter

    public int Id  get; set; 

    public int PokemonId  get; set; 

    [ForeignKey("PokemonId")]
    public Pokemon Pokemon  get; set; 


【讨论】:

【参考方案3】:

抱歉,我一直在寻找错误的地方来寻找答案。在调试器中逐步完成后,我可以看到我的 Pokemon 查询确实返回了所需的结果:附加了许多遭遇的 pokemon。我的问题似乎出在其他地方(特别是:我看到的 JSON 化对象通过我的 Web 前端截断了遇到数组以仅包含第一个结果)。

我将发布一个包含正确问题的新问题,并在发现问题后从此处链接到该问题。

【讨论】:

是的,在输出中发现一个 json 序列化错误。 好的,所以问题是 JSON 序列化程序检测到自引用循环(因为 Pokemon 引用了 Encounters,而 Encounters 又引用了 pokemon)并在 Debug 输出中抛出了一个错误(我错过了重复)以避免进入无限循环。这个问题的解决方案在这里:***.com/questions/17313632/…

以上是关于EF6 Linq 查询。仅包括返回子表的第一个条目的主要内容,如果未能解决你的问题,请参考以下文章

LINQ 和 EF6:创建模型时无法使用上下文

EF6+ / 7 添加了我可以添加更新子表的任何方式吗?

Python - BS4 - 仅使用表头+保存为字典从维基百科表中提取子表

Linq:高性能数据库查询仅查询每个第 n 个元素

基于条件比较两个子表的聚合返回记录

Linq包括在嵌套组中,通过查询