【问题标题】:generalise where clause in linq query概括 linq 查询中的 where 子句
【发布时间】:2016-10-06 02:48:25
【问题描述】:

我有以下 linq 查询:

    var fileDocuments = (
        from doc in fileUploads
        from invoice in
            (
                from inv in _dbContext.SupplierInvoiceHeaders
                where inv.InvoiceDocumentId == doc.ID || inv.JobSheetInvoiceId == doc.ID
                select inv
                ).DefaultIfEmpty()
        join pos in _dbContext.PurchaseOrders on invoice.PurchaseOrder.PurchaseOrderId equals pos.PurchaseOrderId into poss
        from po in poss.DefaultIfEmpty()
        join hdf in _dbContext.HelpDeskFaults on po.HelpdeskFaultId equals hdf.ID into hdfpo
        from hs in hdfpo.DefaultIfEmpty()
        join store1 in _dbContext.Stores on hs.StoreID equals store1.ID into hsf
        from hdfStore in hsf.DefaultIfEmpty()
        join js in _dbContext.JobSheets on invoice.SupplierInvoiceHeaderId equals js.SupplierInvoiceHeaderID into jss
        from jobSheets in jss.DefaultIfEmpty()
        join ch in _dbContext.ChildProjects on po.ChildProjectId equals ch.ID into chs
        from childProjects in chs.DefaultIfEmpty()
        join ph in _dbContext.ProjectHeaders on childProjects.ProjectHeaderID equals ph.ID into phs
        from projectHeaders in phs.DefaultIfEmpty()
        join ppmsl in _dbContext.PpmScheduleLines on projectHeaders.PPMScheduleRef equals ppmsl.ID into ppsmsls
        from ppmScheduleLines in ppsmsls.DefaultIfEmpty()
        join ss2 in _dbContext.Stores on ppmScheduleLines.StoreID equals ss2.ID into ssts
        from store2 in ssts.DefaultIfEmpty()
        where getJobWhereClause(invoice, hs, ppmScheduleLines, doc) 
        select new
        {
            doc.ID,
            JobSheetId = jobSheets.DocumentID,
            doc.Name,
            doc.DateCreated,
            doc.StoreID,
            StoreName = doc.Store.Name,
            DocumentType = doc.DocumentType.Name,
            doc.DocumentTypeID
        })
        .AsEnumerable()
        .Distinct()
        .Select(d => new JobDocumentDto
        {
            ID = d.ID,
            DocumentID = (d.JobSheetId) ?? d.ID,
            DocumentName = d.Name,
            DateCreated = d.DateCreated.ToString("dd/MM/yyyy"),
            StoreName = d.StoreName,
            DocumentTypeName = d.DocumentType,
            DocumentTypeId = d.DocumentTypeID
        }).OrderByDescending(x => x.ID);
    return fileDocuments;

我试图将 where 子句分成一个 func:

    Func<SupplierInvoiceHeader, HelpDeskFault, PpmScheduleLineEntity, DocumentUploadEntity, bool> getJobWhereClause = (invoice, helpDeskFault, ppmScheduleLine, doc) =>
    {
        if (!string.IsNullOrEmpty(jobSearchParams.PIR) && string.IsNullOrEmpty(jobSearchParams.StoreName))
        {
            return invoice.PurchaseInvoiceReference == jobSearchParams.PIR;
        }
        if (string.IsNullOrEmpty(jobSearchParams.PIR) && !string.IsNullOrEmpty(jobSearchParams.StoreName))
        {
            return helpDeskFault.Store.Name.Contains(jobSearchParams.StoreName) || doc.Store.Name.Contains(jobSearchParams.StoreName) || ppmScheduleLine.Store.Name.Contains(jobSearchParams.StoreName);     
        }

        return invoice.PurchaseInvoiceReference == jobSearchParams.PIR && (helpDeskFault.Store.Name.Contains(jobSearchParams.StoreName) || doc.Store.Name.Contains(jobSearchParams.StoreName) || ppmScheduleLine.Store.Name.Contains(jobSearchParams.StoreName));
    };

我收到以下错误消息:

测试方法 IntegrationTests.Services.DocumentUploadServiceTests.Should_Search_By_PIR 抛出异常:System.NotSupportedException:LINQ 表达式 LINQ to Entities 不支持节点类型“Invoke”。

这是有道理的,因为没有从 func 到 sql 的直接转换,但是有没有办法可以创建一个表达式来实现我所追求的?

【问题讨论】:

  • 只需将该变量声明为 Expression>,而不是纯 Func
  • 我已经尝试过了,但在进行实际相等性检查时出现编译器错误:无法将带有语句体的 lambda 表达式转换为表达式树。
  • 是的,我错过了它不是 lambda 表达式。您可以将其转换为带有“?:”运算符的单个语句吗?
  • 如果我这样做,我会失去可读性。我需要阅读表达式树
  • LinqKit 是你所需要的

标签: c# entity-framework linq entity-framework-4


【解决方案1】:

最简单的方法就是使用扩展方法并返回一个IQueryable,类似这样(只需填写...):

public static IQueryable<fileUpload> FilterByThisStuff(this DbSet<fileUpload> db, ... invoice, ... helpDeskFault, ... ppmScheduleLine, ... doc)
{
    if (!string.IsNullOrEmpty(jobSearchParams.PIR) && string.IsNullOrEmpty(jobSearchParams.StoreName))
    {
        return db.Where(invoice=>invoice.PurchaseInvoiceReference == jobSearchParams.PIR);
    }
    if (string.IsNullOrEmpty(jobSearchParams.PIR) && !string.IsNullOrEmpty(jobSearchParams.StoreName))
    {
        return db.Where(...);     
    }

    return db.Where(...);
};

我注意到你那里有很多连接。考虑使用导航属性实际构建模型。在任何情况下,您都可以像使用任何其他 LINQ 方法一样使用上述方法,否则您将需要创建一些具体的类,以便可以在扩展方法中使用它。最简单的方法:

var results=db.FileUploads
  .FilterByThisStuff(a,b,c,d)
  .Select(...)
  .OrderBy(...)
  .Take(...);

【讨论】:

    猜你喜欢
    • 2020-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-14
    • 2010-10-28
    相关资源
    最近更新 更多