linq EF无法翻译

kfgdxczn  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(139)

我在转换查询、ToList()、AsEnumerable等方面遇到问题。
我需要构造或创建共享查询
分支机构-〉客户-〉部分收款-〉部分收款客户-〉部分收款-〉部分收款。
你帮我怎么做是最好的思考如何做和分享查询。
i使用投影等经由Graphql访问储存库。

public IQueryable<CustomerTableGraphQL> BranchTableReportTest(DateTime actualTime, long userId)
{
    var r =
    (
        from b in _dbContext.Branches
        let t = Customers(b.Id).ToList()
        select new CustomerTableGraphQL
        {
            Id = b.Id,
            Name = b.Name,
            Children =
            (
                from c in t
                select new CustomerTableGraphQL
                {
                    Id = c.Id,
                    Name = c.Name
                }
            )
            .AsEnumerable()
        }
    );

    return r;
}

public IQueryable<Customer> Customers(long branchId) => 
    _dbContext.Customers.Where(x => x.BranchId.Value == branchId).ToList().AsQueryable();

如何在查询之间共享iquearable的一些示例

t98cgbkg

t98cgbkg1#

使用ToList/AsEnumerable等完全抵消了使用IQueryable的潜在好处。如果您的代码需要这样做而不是返回IQueryable<TEntity>,那么您应该返回IEnumerable<TResult>,其中TResult是您要返回的任何实体或DTO/ViewModel。
IQueryable<TEntity>存储库模式的一个示例如下:

public IQueryable<Customer> GetCustomersByBranch(long branchId) => 
    _dbContext.Customers.Where(x => x.BranchId.Value == branchId);

通常情况下,我甚至没有一个仓库方法来实现这一点,我只用途:

public IQueryable<Customer> GetCustomers() => 
    _dbContext.Customers.AsQueryable();

...因为“每个分支”对于使用者来说足够简单,不需要为每个可能的筛选条件添加方法。在本例中需要AsQueryable只是因为我想确保结果匹配IQueryable类型转换。当表达式有Where子句时,它会自动解释为IQueryable结果。
因此,调用存储库的“GetCustomers()”方法的调用者将如下所示:

// get customer details for our branch.
var customers = _Repository.GetCustomers()
    .Where(x => x.BranchId == branchId)
    .OrderBy(x => x.LastName)
    .ThenBy(x => x.FirstName)
    .Select(x => new CustomerSummaryViewModel
    {
         CustomerId = x.Id,
         FirstName = x.FirstName,
         LastName = x.LastName,
         // ...
    }).Skip(pageNumber * pageSize)
    .Take(pageSize)
    .ToList();

在本例中,存储库公开了一个基本查询以获取数据,但不执行/具体化任何内容。然后,该调用的使用者可以自由执行以下操作:

  • 按分支筛选数据,
  • 排序数据、
  • 将数据向下投影到所需的视图模型
  • 对结果进行分页

...在查询实际运行之前。这只提取在查询中进行筛选和排序后填充VM所需的数据页。该Repository方法可以为许多不同的调用提供服务,而不需要参数、代码或专用方法来完成所有这些操作。
返回IQueryable且只公开DbSet的存储库并不是真的有用。它们提供的唯一目的是使单元测试更容易一些,因为模拟存储库比模拟DbContext和DbSet更简单。存储库模式开始帮助的地方是在数据上实施标准化的规则/过滤器。例如,软删除标志或多-租户系统,其中的行可能属于不同的客户端,因此用户应该只搜索/拉取一个租户的数据。这也扩展到了诸如在返回数据之前进行授权检查之类的细节。其中一些可以通过全局查询过滤器之类的东西来管理,但是只要存在关于能够检索哪些数据的公共规则,存储库可以作为一个边界,以确保这些规则得到一致应用。例如,对于软删除检查:

public IQueryable<Customer> GetCustomers(bool includeInactive = false)
{
    var query = _context.Customers.AsQueryable();
    if (!includeInactive)
        query = query.Where(x => x.IsActive);
    return query;
}

可以为存储库指定一个依赖关系,用于查找当前登录的用户并检索其角色、租户信息等,然后使用该依赖关系确保:

  • 用户登录。
  • 只有检索到的数据才可供该用户使用。
  • 如果请求了此用户不应访问的特定数据,则会引发相应的异常。

IQueryable存储库确实需要工作单元作用域模式才能在应用程序中有效地工作。IQueryable查询不会执行,直到出现ToListSingleAnyCount这意味着存储库的调用者最终需要管理存储库正在使用的DbContext的范围,这有时会让开发人员感到困惑,因为他们觉得存储库应该是调用者之间的一个抽象层(服务、控制器等等)和数据访问“层”。(EF)拥有这种抽象意味着增加了许多复杂性,最终必须符合EF的规则如果有明确的需求或利益需要为所有系统都将遵循的存储库严格标准化一个通用的API类方法,则不建议使用IQueryable模式而非常规的IEnumerable类型化结果。IQueryable的优点是灵活性和性能。使用者决定并优化使用来自存储库的数据的方式。这种灵活性扩展到包括同步和异步用例。

ktecyv1j

ktecyv1j2#

EF Core将只转换内联查询代码。此查询将工作:

public IQueryable<CustomerTableGraphQL> BranchTableReportTest(DateTime actualTime, long userId)
{
    var r =
    (
        from b in _dbContext.Branches
        select new CustomerTableGraphQL
        {
            Id = b.Id,
            Name = b.Name,
            Children =
            (
                from c in _dbContext.Customers
                where c.BranchId == b.Id
                select new CustomerTableGraphQL
                {
                    Id = c.Id,
                    Name = c.Name
                }
            )
            .AsEnumerable()
        }
    );

    return r;
}

如果你计划重用查询部分,你必须处理LINQKit和它的ExpandableAttribute(将按要求显示示例)

相关问题