将IQueryable<>类型的对象转换为List<T>类型?

67
我有一个对象。
我想将其转换为List<>,并选择像new { ID = s.ID, Name = s.Name }这样的列。
编辑后:
Marc,你说得对!
但是,由于我的架构限制,我只能访问FindByAll()方法。
它会在中返回整个对象
而我有一个严格的要求(用于为选择标记创建JSON对象)只有两个字段的list<>类型。

如果使用FindByAll(...).Select(s=>new {ID = s.ID, Name = s.Name}).ToList(),会出现什么问题? - Marc Gravell
请注意我的回答下面的评论,如果需要,可以创建自己的类型。如果Json.NET需要可编辑属性,则需要您自己的类型(C#匿名类型是不可变的)。 - Marc Gravell
5个回答

83

那么只需 Select

var list = source.Select(s=>new { ID = s.ID, Name = s.Name }).ToList();

(编辑) 实际上,这种情况下可以推断出名称,所以你可以使用:

var list = source.Select(s=>new { s.ID, s.Name }).ToList();

这会节约一些电子...


根据我的层级,我只能通过linq查询获取整个对象。这就是问题所在。 - Vikas
你能解释一下吗?我不理解这个注释。 - Marc Gravell
6
如果你的意思是需要在层之间返回此对象,那么你需要创建一个带有ID和Name属性的普通类型,并选择(Select)实例化为YourType类型的对象列表,代码如下:s=>new YourType {ID = s.ID, Name = s.Name }).ToList()。 - Marc Gravell
@Brij,有什么问题吗?这很不清楚。看起来你代码的主要问题是ToList()将返回一个List<T>而不是ArrayList - 我猜你的第一步应该是简单地使用var data = .... - Marc Gravell

53

添加以下内容:

using System.Linq

IQueryable<> 上调用 ToList()


1
@pauliephonic 你应该开始使用(双关语意)ReSharper,这样你就再也不用输入另一个using语句了;-) - bytedev
2
简单、精确、美丽! - Papa Ccompis

8
List类的构造函数可以为您转换IQueryable:
public static List<TResult> ToList<TResult>(this IQueryable source)
{
    return new List<TResult>(source);
}

或者你当然也可以不使用扩展方法进行转换:
var list = new List<T>(queryable);

不客气。我真的很想知道为什么这个扩展没有一开始就包含在.NET中... - mmmeff
抱歉,我没听懂你的意思。你说的“为什么没有包含这个扩展...”是什么意思?不过它确实可以工作。 - Khadim Ali
6
我的意思是 IQueryable.ToList() 应该早就存在,我们需要自己添加它作为扩展方法感觉有些愚蠢。 - mmmeff

6

System.Linq在IQueryable<>和IEnumerable<>上有一个ToList()方法。然而,这将导致对数据的完全遍历以将其放入列表中。当您执行此操作时,将失去延迟调用的功能。如果这是数据的消费者,那么这并不是什么大问题。


2
以下是我拼凑在一起的几个扩展方法,用于将IQueryable和IEnumerable从一种类型转换为另一种类型(例如DTO)。它主要用于从较大的类型(即数据库中具有不需要字段的行的类型)转换为较小的类型。
这种方法的优点包括:
- 几乎不需要编写代码即可使用——只需简单调用.Transform<DtoType>()即可。 - 它的工作方式与.Select(s=>new{...})完全相同,即当与IQueryable一起使用时,它会生成最佳SQL代码,排除DtoType没有的Type1字段。
LinqHelper.cs:
public static IQueryable<TResult> Transform<TResult>(this IQueryable source)
{
    var resultType = typeof(TResult);
    var resultProperties = resultType.GetProperties().Where(p => p.CanWrite);

    ParameterExpression s = Expression.Parameter(source.ElementType, "s");

    var memberBindings =
        resultProperties.Select(p =>
            Expression.Bind(typeof(TResult).GetMember(p.Name)[0], Expression.Property(s, p.Name))).OfType<MemberBinding>();

    Expression memberInit = Expression.MemberInit(
        Expression.New(typeof(TResult)),
        memberBindings
        );

    var memberInitLambda = Expression.Lambda(memberInit, s);

    var typeArgs = new[]
        {
            source.ElementType, 
            memberInit.Type
        };

    var mc = Expression.Call(typeof(Queryable), "Select", typeArgs, source.Expression, memberInitLambda);

    var query = source.Provider.CreateQuery<TResult>(mc);

    return query;
}

public static IEnumerable<TResult> Transform<TResult>(this IEnumerable source)
{
    return source.AsQueryable().Transform<TResult>();
}

对于从Hibernate/NHibernate世界转到Linq的人来说,其功能与NHibernate的**.SetResultTransformer(Transformers.AliasToBean(typeof(DtoType)))或Hibernate的.setResultTransformer(Transformers.aliasToBean(DtoType.class))**大致相同。 - Vedran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接