lmc*_*iro 30 linq-to-entities tuples anonymous-types linq-to-nhibernate c#-7.0
C#的新版本就在那里,有了新的功能元组类型:
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new {
id = o.Id,
name = o.Name,
})
.First();
return (id: obj.id, name: obj.name);
}
Run Code Online (Sandbox Code Playgroud)
有没有办法将我的匿名类型对象obj转换为我想要返回的元组而没有按属性映射属性(假设属性的名称匹配)?
上下文在ORM中,我的SomeType对象有很多其他属性,它被映射到包含大量列的表.我想做一个只带来ID和NAME的查询,所以我需要将匿名类型转换为元组,或者我需要ORM Linq Provider知道如何理解元组并将属性相关列放在SQL select子句中.
Dav*_*d L 20
简短的回答是否定的,在C#7的当前形式中,没有框架内的方式来逐字实现您的目标,因为您想要完成:
因为Query<SomeType>
暴露了一个IQueryable
,所以必须对表达式树进行任何类型的投影.Select(x => new {})
.
有一个开放的roslyn问题用于添加此支持,但它尚不存在.
因此,在添加此支持之前,您可以手动将匿名类型映射到元组,或者返回整个记录并将结果直接映射到元组以避免两个映射,但这显然效率低下.
虽然由于缺乏支持以及无法在.Select()
投影中使用参数化构造函数,这个限制目前被纳入Linq-to-Entities ,但Linq-to-NHibernate和Linq-to-Sql都允许以创建的形式进行攻击System.Tuple
在.Select()
投影中使用new ,然后使用.ToValueTuple()扩展方法返回ValueTuple :
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new System.Tuple<int, string>(o.Id, o.Name))
.First();
return obj.ToValueTuple();
}
Run Code Online (Sandbox Code Playgroud)
由于System.Tuple可以映射到表达式,因此您可以从表中返回数据子集,并允许框架处理映射到C#7元组.然后,您可以使用您选择的任何命名约定来解构参数:
(int id, string customName) info = GetSomeInfo();
Console.Write(info.customName);
Run Code Online (Sandbox Code Playgroud)
Pat*_*man 18
当然,通过从LINQ表达式创建元组:
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
Run Code Online (Sandbox Code Playgroud)
根据关于前C#7元组的另一个答案,您可以使用AsEnumerable()
以防止EF混淆.(我对EF没什么经验,但这应该:)
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.AsEnumerable()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
Run Code Online (Sandbox Code Playgroud)
尽管表达式树当前不支持元组文字,但这并不意味着不支持该ValueTuple
类型。只需显式创建它即可。
public (int id, string name) GetSomeInfo() =>
Query<SomeType>()
.Select(o => ValueTuple.Create(o.Id, o.Name))
.First();
Run Code Online (Sandbox Code Playgroud)