在 LinqSelect 中创建元组

我使用 C # 和.NET Framework 4.5.1从 SQL Server 数据库中检索数据,使用 Entity Framework 6.1.3。

我有这个:

codes = codesRepo.SearchFor(predicate)
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();

当我运行它的时候,我得到了这样的信息:

Only parameterless constructors and initializers are supported in LINQ 实体。

我不知道如何创建 Tuple,因为我找到的所有示例大多与此类似。

我试过这个:

codes = codesRepo.SearchFor(predicate)
.Select(c => Tuple.Create(c.Id, c.Flag))
.ToList();

得到这个错误:

LINQtoEntity 不识别该方法 ‘ System. Tuple‘2[ System. String,System. Byte ] 创建[ String,Byte ](System.String,Byte)’方法和此方法 无法翻译成存储表达式。

问题出在哪里?

107841 次浏览

试试这个:

codes = codesRepo.SearchFor(predicate)
.Select(c => Tuple.Create(c.Id, c.Flag))
.ToList();

被告知这是不接受在 LINQ 的实体。

另一种选择是在选择之前将结果放入内存。如果要执行此操作,我建议在。AsEnumable () ,因为它意味着只提取所需的结果,而不是提取整个表然后进行过滤。

codes = codesRepo.SearchFor(predicate).AsEnumerable()
.Select(c => Tuple.Create(c.Id, c.Flag))
.ToList();

as well Tuple.Create(c.Id, c.Flag) could be changed to new Tuple(c.Id, c.Flag) if you want to make the code a bit more explicit in the tuples types

实体链接中,你可以投影到匿名类型或 DTO 上。为了避免这个问题,你可以使用 AsEnumerable扩展方法:

codes = codesRepo.SearchFor(predicate).AsEnumerable().
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();

这个方法允许您使用 Linq to Object而不是 实体链接,因此在调用它之后,您可以将查询的结果投影到任何您需要的地方。使用 AsEnumerable代替 ToList的优点是,AsEnumerable不执行查询,而是保留延迟执行。在调用这些方法之一之前,最好先过滤数据。

While the 回答 by 八面体 works, it's better to first project the query result into anonymous type, and then switch to enumerable and convert it to tuple. This way your query will retrieve from the data base only the fields needed.

codes = codesRepo.SearchFor(predicate)
.Select(c => new { c.Id, c.Flag })
.AsEnumerable()
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();

注: 以上规则适用于 EF6。EF Core 通过 tuple 构造函数自然地支持 tuple (在投影中或作为连接/组键) ,例如,原始查询可以简单地工作

codes = codesRepo.SearchFor(predicate)
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();

而非 Tuple.Create方法(EF Core 2.x)。

使用此方法执行此操作并使用异步。

var codes = await codesRepo.SearchFor(predicate)
.Select(s => new
{
Id = s.Id,
Flag = s.Flag
}).FirstOrDefaultAsync();


var return_Value = new Tuple<string, byte>(codes.Id, codes.Flag);

现在您可以使用更简单的语法来创建 ValueTuples 了。

codes = codesRepo.SearchFor(predicate)
.Select(c => new { c.Id, c.Flag })
.AsEnumerable()
.Select(c => (c.Id, c.Flag))
.ToList();

现在您甚至可以命名 tuple 的属性:

codes = codesRepo.SearchFor(predicate)
.Select(c => new { c.Id, c.Flag }) // anonymous type
.AsEnumerable()
.Select(c => (Id: c.Id, Flag: c.Flag)) // ValueTuple
.ToList();

因此,您可以将它作为 Id 或 Flag 访问,而不是使用它作为 Item1或 Item2。

在匿名和元组之间选择上有更多文件

我的建议是: 这已经让我注意到了好几次类型名称:

一些无聊的例子:

    private Tuple<string, byte> v1()
{
return new Tuple<string, byte>("", 1);
}


private (string, int) v2()
{
return ("", 1);
}


private (string Id, byte Flag) v3()
{
return ("", 1);
}

问候。