使用EF将连接结果投影到DTO时,如何动态构建“where”子句?在NHibernate中,这很容易实现,但我无法弄清楚如何使用Entity Framework执行此操作。 只是为了澄清,我不想过滤对象,我想要构建sql。
这就是我想要做的。
private async Task<List<InvoiceInfo>> GetDataWithManualProjection()
{
var query = (from i in db.Invoices
join cj in db.CustomerJobs on i.CustomerJobID equals cj.ID
join c in db.Customers on cj.CustomerId equals c.ID
let invoice = i
let customer = c
let customerJob = cj
select new InvoiceInfo()
{
Number = invoice.InvoiceNumber,
Balance = invoice.InvoiceBalance,
PrePay = customer.PrepaymentBalance
})
.AsQueryable();
BuildWhereClause(filter, query);
return await q.ToListAsync();
}
private void BuildWhereClause(InvoicesFilter filter, ref IQueryable<Invoice> q)
{
if (string.IsNullOrWhiteSpace(filter.ClientName) == false)
{
switch (filter.ClientNameFilterOptions)
{
case ClientNameFilterOptions.Contains:
q = q.Where(x => x.ClientName.Contains(filter.ClientName));
break;
case ClientNameFilterOptions.EqualTo:
q = q.Where(x => x.ClientName == filter.ClientName);
break;
case ClientNameFilterOptions.StartsWith:
q = q.Where(x => x.ClientName.StartsWith(filter.ClientName));
break;
}
}
if (filter.InvoiceBalance.HasValue)
{
var invoiceBalance = filter.InvoiceBalance.Value;
switch (filter.InvoiceBalanceComparisonOperator)
{
case ComparisonOperator.EqualTo:
q = q.Where(x => x.InvoiceBalance == invoiceBalance);
break;
case ComparisonOperator.GreaterThan:
q = q.Where(x => x.InvoiceBalance > invoiceBalance);
break;
case ComparisonOperator.GreatherThanOrEqualTo:
q = q.Where(x => x.InvoiceBalance >= invoiceBalance);
break;
case ComparisonOperator.LessThan:
q = q.Where(x => x.InvoiceBalance < invoiceBalance);
break;
case ComparisonOperator.LessThanOrEqualTo:
q = q.Where(x => x.InvoiceBalance <= invoiceBalance);
break;
}
}
if (string.IsNullOrWhiteSpace(filter.Address) == false)
{
q = q.Where(x => x.CustomerJob.BillingAddress1 == filter.Address);
}
if (string.IsNullOrWhiteSpace(filter.City) == false)
{
q = q.Where(x => x.CustomerJob.BillingCity == filter.City);
}
if (string.IsNullOrWhiteSpace(filter.ZipCode) == false)
{
q = q.Where(x => x.CustomerJob.BillingZip == filter.ZipCode);
}
if (filter.InvoiceFrequency != InvoiceFrequency.NotSet)
{
q = q.Where(x => x.InvoiceFrequency == filter.InvoiceFrequency);
}
if (filter.InvoiceStatus != InvoiceStatus.NotSet)
{
q = q.Where(x => x.Status == filter.InvoiceStatus);
}
if (filter.StartDate.HasValue)
{
q = q.Where(x => x.InvoiceStartDate >= filter.StartDate.Value);
}
if (filter.EndDate.HasValue)
{
q = q.Where(x => x.InvoiceEndDate <= filter.EndDate.Value);
}
if (filter.PaymentMethod != MethodOfPayment.NotSet)
{
q = q.Where(x => x.MethodOfPayment == filter.PaymentMethod);
}
if (filter.InvoiceNumbers.Any())
{
q = q.Where(x => filter.InvoiceNumbers.Contains(x.InvoiceNumber));
}
if (string.IsNullOrWhiteSpace(filter.LineItemDescription) == false)
{
q = q.Where(x => x.LineItems.Any(l => l.InvoiceDescription.Contains(filter.LineItemDescription)));
}
if (filter.HasCCOnFile)
{
throw new NotImplementedException();
}
}
答案 0 :(得分:2)
您可以提前应用Invoice
过滤器,并在LINQ查询中使用生成的IQueryable
:
var invoices = db.Invoices.AsQueryable();
BuildWhereClause(filter, ref invoices);
var query = (from i in invoices
join cj in db.CustomerJobs on i.CustomerJobID equals cj.ID
...
答案 1 :(得分:0)
您的私有方法需要具有以下语法:
private IQueryable<InvoiceInfo> BuildWhereClause(Expression<Func<InvoiceInfo,bool>> filter,
IQueryable<InvoiceInfo> q)
{
return q.Where(filter);
}
您不需要在查询结束时调用AsQueryable
方法
如果要将过滤器应用于实体而不是投影,则需要通过几个步骤编写查询,例如:
IQueryable<Invoice> query= db.Invoices;
BuildWhereClause(filter,ref query);
var result= (from i in query
join cj in db.CustomerJobs on i.CustomerJobID equals cj.ID
join c in db.Customers on cj.CustomerId equals c.ID
select new InvoiceInfo()
{
Number = i.InvoiceNumber,
Balance = i.InvoiceBalance,
PrePay = c.PrepaymentBalance
});
此外,您不需要在查询中使用let
子句,每次使用时都会应用额外的投影。