我有一个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) {
// ...
}
有没有一种方法,我可以做到这一点?
由于您突出(选择)的类型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);
这可以通过使用Dynamic Linq来实现。
而对于.NET的核心 - System.Linq.Dynamic.Core
使用动态的LINQ,你可以在你的SELECT和WHERE作为字符串传递。
使用你的榜样,然后你可以这样做:
IQueryable<Person> query = context.Persons
.Select("new Person { FirstName = p.FirstName }");
试试这个代码:
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);
}