【问题标题】:Using LINQ with Select and Distinct Methods将 LINQ 与 Select 和 Distinct 方法一起使用
【发布时间】:2019-05-22 02:34:16
【问题描述】:

如果我在 LINQPad 中使用以下代码来查询我的数据库,我会得到想要的结果:

LoadTables.Where(o=> o.Approver== "Name Name" ||o.Approver== "Name.Name").Select(o=>o.SubmittedBy).ToList().Distinct()

但是,如果我修改它并将其放入我的代码中,我会收到错误:

public IEnumerable<LoadTable> TableList;
TableList = _context.LoadTable.Where(o => o.Approver == GetADDetails.displayName || o.Approver == GetADDetails.userName).Select(o => o.SubmittedBy).ToList().Distinct();

返回的错误是:

无法隐式转换类型'System.Collections.Generic.IEnumerable&lt;string&gt;' to 'System.Collections.Generic.IEnumerable&lt;App.Models.LoadTable&gt;' An explicit conversion exists.

我哪里错了?

有关上下文,请参阅此处的先前问题:

Using LINQ to loop through data and display in a table

目前它正在为每场比赛返回一个新表,我正试图让它为每个用户返回一个表。

【问题讨论】:

  • 您调用了Select(o =&gt; o.SubmittedBy),因此您只返回该字符串SubmittedBy 而不是完整的LoadTable 对象。因此返回的序列是IEnumerable&lt;string&gt; 而不是IEnumerable&lt;LoadTable&gt;
  • 代码...Select(o=&gt;o.SubmittedBy) 正在创建一个可枚举的字符串。如果你想要LoadTable 的枚举,那么你需要...Select(o=&gt; new LoadTable{ SubmittedBy = o.SubmittedBy}) 之类的东西。虽然看起来你只想要字符串。你知道Select 在做什么吗?
  • 删除.Select(o =&gt; o.SubmittedBy)
  • @asd 对我来说似乎 OP 正在寻找类似 @​​987654335@ 的东西(查询提供程序可能不支持)。
  • @René Vogt 正是这样,我目前正在为每场比赛获得一个新表格,我只想要一个用于每个唯一用户名的表格。

标签: c# asp.net linq


【解决方案1】:

从 Linq 表达式中删除 Select(o =&gt; o.SubmittedBy) 并在 ToList() 之前放置 Distinct()

public IEnumerable<LoadTable> TableList;
TableList = _context.LoadTable.Where(o => o.Approver == GetADDetails.displayName || 
  o.Approver == GetADDetails.userName).Distinct().ToList();

【讨论】:

  • 你觉得Distinct会在这里做什么?
  • @DavidG 当您创建 ToList() 时,EF 将针对 BBDD 的查询具体化。如果您将Distinct() 放在ToList() 之后,您将从数据库中收到所有记录,稍后使用Linq 过滤它们。
  • 是的,但是如果返回所有字段,包括表的主键,您认为这会做什么? (提示:不会有任何区别。
  • @DavidG 是的,你是对的,因为它可以恢复所有字段。这只是一个好习惯。
【解决方案2】:

您正在选择一个字符串属性

**.Select(o => o.SubmittedBy)**

这个返回IEnumerable&lt;string&gt;

你需要像下面这样的东西

_context.LoadTable.Where(o => o.Approver == GetADDetails.displayName || o.Approver == GetADDetails.userName).Distinct().GroupBy(p => p.SubmittedBy).Select(grp => grp.FirstOrDefault());

【讨论】:

  • 虽然这确实有效,但每个 SubmittedBy 会返回 1 个结果,我猜来自 FirstOrDefault()?
  • 是的,它将返回每条记录的第一个或默认值。说结果是 [1,1,1,2,2,3] 它会返回 [1,2,3] 这只是一个例子
  • 因此,如果我使用 FirstOrDefault(),我如何只停止第一个结果通过子 for 循环?请参阅我之前的问题以获取信息stackoverflow.com/questions/56233558/… 谢谢!
  • 这样做:_context.LoadTable.Where(o => o.Approver == GetADDetails.displayName || o.Approver == GetADDetails.userName).Distinct().GroupBy(p => p .SubmittedBy).Select(s => s);将返回按 Submitted 分组的 LoadTable Single 列表...是您需要的吗?
  • @GabrielScavassa 我相信是这样,但这会引发无法转换类型错误。可能是由于我宣布列表的方式。我不知道如何解决这个问题。
【解决方案3】:

唉,你忘了告诉我们_context.LoadTable 返回的序列中有哪些类型的对象。查看您的代码,它似乎返回了一个可枚举的对象序列,其中每个对象至少有一个属性SubmittedBy

看你的错误,SubmittedBy 似乎是一个字符串属性。

如果您将代码拆分为更小的部分并使用正确的标识符,您很快就会发现问题。

让我们检查您的代码:

IEnumerable<LoadTable> TableList = _context.LoadTable
    .Where(o => o.Approver == GetADDetails.displayName || o.Approver == GetADDetails.userName)
    .Select(o => o.SubmittedBy)
    .ToList()
    .Distinct();

_context.LoadTable 返回一个我不知道的 IEnumerable 序列,所以我们假设它是 Notes 的序列:

IEnumerable<Note> notes = _context.LoadTable;

可能是LoadTable 返回IEnumerable 而不是IEnumerabl&lt;Note&gt;,在这种情况下您应该转换加载的表。

接下来的陈述:

IEnumerableM<Note> notesApprovedByUser = notes
    .Where(note => note.Approver == GetADDetails.displayName 
                || note.Approver == GetADDetails.userName);
IEnumerable<string> submitters = notesApprovedByUser
    .Select(note => note.SubmittedBy);
List<string> submitterList = submitters.ToList();
IEnumerable<string> distinctSubmitters = submitterList.Distinct();

不难看出,字符串序列不能轻易转换为LoadTables序列。

问题是:您想要唯一的LoadTables,还是想要为每个提交者提供所有历史记录?在这种情况下,您必须使用Groupby 而不是Select

.Where(note => ...)
.GroupBy(note => note.SubmittedBy,  // make groups of Notes submitted by the same submitter
   // parameter resultSelector: take every submitter and all notes that
   // were submitted by this submitter to make a new object
   (submittedBy, notesSubmittedByThisSubmitter) => new
   {
       // select the properties you plan to use
       Submitter = submittedBy
       LoadTables = notesSubmittedByThisSubmitter.Select(note => new LoadTable
       {
           ... again: select the properties you need
       })
       .ToList(),
   });

记住:保留IEnumerable&lt;...&gt;IEnumerable&lt;...&gt; as long as possible. If not necessary, don't do aToList()before you return. If your query returns 1000 items, and your caller will only doFirstOrDefault, orTake(3).ToList()`,创建完整列表会浪费处理能力

【讨论】:

    猜你喜欢
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-24
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    相关资源
    最近更新 更多