【发布时间】:2020-06-08 15:13:30
【问题描述】:
我希望能够动态地将 GroupBy 子句提供给 EF 查询,而不是硬编码 GroupBy 子句。
希望这段代码能说明我想要做什么:
以下是简单图书馆图书借阅系统的一些简单实体:
public class Book
{
public int Id { get; set; }
public string Isbn { get; set; }
public string Title { get; set; }
public IList<Loan> Loans { get; set; }
}
public class Member
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
public IList<Loan> Loans { get; set; }
}
public class Loan
{
public int Id { get; set; }
public int BookId { get; set; }
public int MemberId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public Book Book { get; set; }
public Member Member { get; set; }
}
我有这两个视图模型来帮助我的 EF 查询:
public class DoubleGroupByClause
{
public string GroupByFieldValue1 { get; set; }
public string GroupByFieldValue2 { get; set; }
}
public class QueryRow
{
public string GroupBy1 { get; set; }
public string GroupBy2 { get; set; }
public int Value { get; set; }
}
我可以运行以下代码,它会返回一个 QueryRow 对象列表,它等于 Loans 的总数,按书籍和成员年龄分组:
var rows = _db.Loans
// note that the GroupBy method params are hard-coded
.GroupBy( x => new DoubleGroupByClause{GroupByFieldValue1 = x.BookId, GroupByFieldValue2 = x.Member.Age} )
.Select(x => new QueryRow
{
RowId = x.Key.GroupByFieldValue1.ToString(),
ColId = x.Key.GroupByFieldValue2.ToString(),
Value = x.Count()
})
.ToList();
这很好用,并返回一个类似于以下内容的列表:
GroupBy1 GroupBy2 Value
(BookId) (Age) (Loans)
======== ======== =====
45 14 23
45 15 37
45 16 55
72 14 34
72 15 66
72 16 9
现在解决问题: 我希望能够从查询本身之外指定我的 GroupBy 子句。这个想法是我希望分组的两个字段应该保存在类似于变量的东西中,然后在运行时应用于查询。我非常接近做到这一点。这是我的工作:
// holding the two group by clauses here
Func<Loan, string> groupBy1 = g => g.BookId.ToString();
Func<Loan, string> groupBy2 = g => g.Member.Age.ToString();
// applying the clauses into an expression
Expression<Func<Loan, DoubleGroupByClause>> groupBy = g => new DoubleGroupByClause {GroupByFieldValue1 = groupBy1.Invoke(g), GroupByFieldValue2 = groupBy2.Invoke(g)};
var rows = _db.Loans
.GroupBy(groupBy) // applying the expression into the GroupBy clause
.Select(x => new QueryRow
{
RowId = x.Key.GroupByFieldValue1.ToString(),
ColId = x.Key.GroupByFieldValue2.ToString(),
Value = x.Count()
})
.ToList();
这编译得很好,但我在运行时收到以下错误:
System.InvalidOperationException: The LINQ expression 'DbSet<Loans>
.GroupBy(
source: m => new DoubleGroupByClause{
GroupByFieldValue1 = __groupBy1_0.Invoke(m),
GroupByFieldValue2 = __groupBy2_1.Invoke(m)
}
,
keySelector: m => m)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
我想我已经很接近了,但是任何人都可以帮我解决这个问题吗?
可能有一种更简单的方法可以做到这一点,所以我愿意接受任何建议。希望代码说明了我想要实现的目标。
【问题讨论】:
标签: c# entity-framework linq entity-framework-core