实体框架何处计算财产的条款

时间:2018-06-05 06:23:49

标签: entity-framework linq expression calculated-field

我有以下型号:

public class Account
{
    public Guid Id{ get; set; }

    [Filterable]
    public string Code{ get; set; }

    [Filterable]
    public string AccountStatus { get; set; }
}

正在根据AccountStatusStartDate的值计算属性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 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'的accountStatus时,我得到以下运行时警告:

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子句添加自定义翻译以及排序和计数?

1 个答案:

答案 0 :(得分:1)

您计算该属性的业务逻辑目前很简单,因此可以内联:

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