Skip to main content
 首页 » 编程设计

linq-to-entities之将匿名类型转换为新的C#7元组类型

2024年10月01日2798°冷暖

那里是C#的新版本,具有有用的新功能Tuple Types:

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); 
} 

有没有一种方法可以将我的匿名类型对象obj转换为要返回的元组,而无需按属性映射属性(假定属性名称匹配)?

上下文位于ORM中,我的SomeType对象具有许多其他属性,并且映射到具有很多列的表。我想执行一个仅带ID和NAME的查询,所以我需要将匿名类型转换为元组,或者我需要ORM Linq提供程序知道如何理解元组并将与属性相关的列放在SQL select子句中。

请您参考如下方法:

简短的答案是没有。在C#7的当前形式中,没有框架内的方法可以完全实现目标,因为您想实现以下目标:

  • 实体对
  • 映射到列
  • 的子集
  • 通过直接映射到C#7元组来避免从自定义或匿名类型到C#7元组的逐个属性映射。

  • 由于 Query<SomeType>公开了 IQueryable,因此必须对表达式树 .Select(x => new {})进行任何类型的投影。

    有一个 open roslyn issue用于添加此支持,但尚不存在。

    结果,在添加此支持之前,您可以手动将匿名类型映射到元组,或者返回整个记录并将结果直接映射到元组,以避免两次映射,但这显然效率低下。

    尽管由于缺乏支持以及无法在 .Select()投影中使用参数化构造函数而使此限制目前流入Linq-to-Entities,但是Linq-to-NHibernate和Linq-to-Sql都允许以在 System.Tuple投影中创建一个新的 .Select(),然后使用 .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(); 
    } 
    

    由于System.Tuple可以映射到表达式,因此您可以从表中返回数据的子集,并允许框架处理到C#7元组的映射。然后,您可以使用选择的任何命名约定来解构参数:
    (int id, string customName) info = GetSomeInfo(); 
    Console.Write(info.customName);