Entity Framework 用于计算的 Where 子句 属性
Entity Framework Where Clause for Calculated property
我有以下型号:
public class Account
{
public Guid Id{ get; set; }
[Filterable]
public string Code{ get; set; }
[Filterable]
public string AccountStatus { get; set; }
}
属性 AccountStatus
的值是根据 StartDate
和 EndDate
的值计算的,所以在我的存储库中的 Linq 查询中,我有以下内容:
public IEnumerable<Account> Get(QueryClause<Account> queryClause, out ForGetCollectionOptions forGetCollectionOptions)
{
using (_dbContext)
{
var result = (
from account in _dbContext.Accounts
select new Account
{
Id = account.ID,
Code = account.Code.Trim(),
AccountStatus = StatusCalculator.GetStatus(account.StartDate, account.EndDate)
}
ApplyFilterClause(ref result, queryClause.FilterClause);
}
}
为了计算帐户状态,我们有以下内容:
public 枚举状态
{
无效,
积极的,
未来
}
public static class StatusCalculator
{
public static string GetStatus(DateTime? startDate, DateTime? endDate)
{
var now = DateTime.Now;
if (startDate != null && startDate > now)
{
return Status.Future.ToString().ToLower();
}
if (startDate != null && endDate == null)
{
return Status.Active.ToString().ToLower();
}
return Status.Inactive.ToString().ToLower();
}
}
问题是,当我尝试过滤例如 'inactive' 的帐户状态时,我收到以下 运行 时间警告:
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'where (GetStatus([account].StartDate, [account].EndDate) == "inactive")' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Count()' could not be translated and will be evaluated locally.
因为计算的 属性 无法翻译,查询将在没有该条件的情况下发送并检索所有数据,然后在本地应用该过滤器,这会损害性能。
如何为 where 子句添加此 属性 的自定义翻译并排序和计数?
你计算属性的业务逻辑目前很简单,所以可以内联:
public IEnumerable<Account> Get(QueryClause<Account> queryClause, out ForGetCollectionOptions forGetCollectionOptions)
{
using (_dbContext)
{
var result = (
from account in _dbContext.Accounts
select new Account
{
Id = account.ID,
Code = account.Code.Trim(),
AccountStatus = (account.StartDate != null && account.EndDate == null)
? "Active"
: (account.StartDate != null && account.StartDate > DateTime.Now)
? "Future"
: "Inactive"
}
ApplyFilterClause(ref result, queryClause.FilterClause);
}
}
这应该使 EF 能够将其转换为 CASE 语句,例如:
SELECT foo
,(CASE
WHEN t.StartDate IS NOT NULL...
WHEN t.StartDate IS NOT NULL AND t.StartDate > GetDate()
ELSE ...
)
FROM bar
我有以下型号:
public class Account
{
public Guid Id{ get; set; }
[Filterable]
public string Code{ get; set; }
[Filterable]
public string AccountStatus { get; set; }
}
属性 AccountStatus
的值是根据 StartDate
和 EndDate
的值计算的,所以在我的存储库中的 Linq 查询中,我有以下内容:
public IEnumerable<Account> Get(QueryClause<Account> queryClause, out ForGetCollectionOptions forGetCollectionOptions)
{
using (_dbContext)
{
var result = (
from account in _dbContext.Accounts
select new Account
{
Id = account.ID,
Code = account.Code.Trim(),
AccountStatus = StatusCalculator.GetStatus(account.StartDate, account.EndDate)
}
ApplyFilterClause(ref result, queryClause.FilterClause);
}
}
为了计算帐户状态,我们有以下内容: public 枚举状态 { 无效, 积极的, 未来 }
public static class StatusCalculator
{
public static string GetStatus(DateTime? startDate, DateTime? endDate)
{
var now = DateTime.Now;
if (startDate != null && startDate > now)
{
return Status.Future.ToString().ToLower();
}
if (startDate != null && endDate == null)
{
return Status.Active.ToString().ToLower();
}
return Status.Inactive.ToString().ToLower();
}
}
问题是,当我尝试过滤例如 'inactive' 的帐户状态时,我收到以下 运行 时间警告:
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'where (GetStatus([account].StartDate, [account].EndDate) == "inactive")' could not be translated and will be evaluated locally.
warn: Microsoft.EntityFrameworkCore.Query[20500]
The LINQ expression 'Count()' could not be translated and will be evaluated locally.
因为计算的 属性 无法翻译,查询将在没有该条件的情况下发送并检索所有数据,然后在本地应用该过滤器,这会损害性能。
如何为 where 子句添加此 属性 的自定义翻译并排序和计数?
你计算属性的业务逻辑目前很简单,所以可以内联:
public IEnumerable<Account> Get(QueryClause<Account> queryClause, out ForGetCollectionOptions forGetCollectionOptions)
{
using (_dbContext)
{
var result = (
from account in _dbContext.Accounts
select new Account
{
Id = account.ID,
Code = account.Code.Trim(),
AccountStatus = (account.StartDate != null && account.EndDate == null)
? "Active"
: (account.StartDate != null && account.StartDate > DateTime.Now)
? "Future"
: "Inactive"
}
ApplyFilterClause(ref result, queryClause.FilterClause);
}
}
这应该使 EF 能够将其转换为 CASE 语句,例如:
SELECT foo
,(CASE
WHEN t.StartDate IS NOT NULL...
WHEN t.StartDate IS NOT NULL AND t.StartDate > GetDate()
ELSE ...
)
FROM bar