使用LINQ(EF核)只选择特定字段

问题描述 投票:4回答:3

我有一个DbContext,我想运行一个查询只返回特定的列,以避免获取所有数据。 问题是,我想用一组字符串指定列名,我想获得的原始类型,即一个IQueryable无需构建一个匿名类型。

下面是一个例子:

// Install-Package Microsoft.AspNetCore.All
// Install-Package Microsoft.EntityFrameworkCore

using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;

public class Person {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class TestContext : DbContext {
    public virtual DbSet<Person> Persons { get; set; }
    public TestContext(DbContextOptions<TestContext> options) : base(options) {
    }
}

class Program {
    static void Main(string[] args) {

        var builder = new DbContextOptionsBuilder<TestContext>();
        builder.UseInMemoryDatabase(Guid.NewGuid().ToString());
        var context = new TestContext(builder.Options);

        context.Persons.Add(new Person { FirstName = "John", LastName = "Doe" });
        context.SaveChanges();

        // How can I express this selecting columns with a set of strings? 
        IQueryable<Person> query = from p in context.Persons select new Person { FirstName = p.FirstName };
    }
}

我想有这样的方法:

static IQueryable<Person> GetPersons(TestContext context, params string[] fieldsToSelect) {
    // ...
}

有没有一种方法,我可以做到这一点?

c# .net-core entity-framework-core
3个回答
9
投票

由于您突出(选择)的类型T的成员为相同类型T,所需Expression<Func<T, T>>可以相对容易Expression类方法是这样被创建:

public static partial class QueryableExtensions
{
    public static IQueryable<T> SelectMembers<T>(this IQueryable<T> source, params string[] memberNames)
    {
        var parameter = Expression.Parameter(typeof(T), "e");
        var bindings = memberNames
            .Select(name => Expression.PropertyOrField(parameter, name))
            .Select(member => Expression.Bind(member.Member, member));
        var body = Expression.MemberInit(Expression.New(typeof(T)), bindings);
        var selector = Expression.Lambda<Func<T, T>>(body, parameter);
        return source.Select(selector);
    }
}

Expression.MemberInit是表达相当于new T { Member1 = x.Member1, Member2 = x.Member2, ... } C#构建体的。

样本用法是:

return context.Set<Person>().SelectMembers(fieldsToSelect);

0
投票

这可以通过使用Dynamic Linq来实现。

而对于.NET的核心 - System.Linq.Dynamic.Core

使用动态的LINQ,你可以在你的SELECT和WHERE作为字符串传递。

使用你的榜样,然后你可以这样做:

IQueryable<Person> query = context.Persons
                        .Select("new Person { FirstName = p.FirstName }");

0
投票

试试这个代码:

string fieldsToSelect = "new Person { FirstName = p.FirstName }"; //Pass this as parameter.

public static IQueryable<Person> GetPersons(TestContext context, string fieldsToSelect) 
{
    IQueryable<Person> query = context.Persons.Select(fieldsToSelect);
}
© www.soinside.com 2019 - 2024. All rights reserved.