C# 如何在C中重用查询

C# 如何在C中重用查询,c#,.net,linq,C#,.net,Linq,我有一个我想重复使用的查询,因为在这两个方法中,连接发生的方式不同 问题1: await (from div in Context.ILevelDataItemValue join pc in Context.Pc on div.PCIdequals pc.Id join f in Context.Fund on div.FundId equals f.Id join di in Context.ildt on div.ildtId equals di.Id join p in Context.

我有一个我想重复使用的查询,因为在这两个方法中,连接发生的方式不同

问题1:

await (from div in Context.ILevelDataItemValue
join pc in Context.Pc
on div.PCIdequals pc.Id
join f in Context.Fund
on div.FundId equals f.Id
join di in Context.ildt
on div.ildtId equals di.Id
join p in Context.vp
on div.PeriodId equals p.Id
**let v = (from v in Context.valwhere v.pcid== pc.Id orderby v.Id select v).DefaultIfEmpty().Last()**
where p.PeriodYear == year && p.PeriodQuarter == quarter
select new TblA
{
pcid = pc.Id,
vid= (int?)v.Id,
fid= f.Id,
PeriodId = p.Id,
ildtid= di.Id,
Value = div.Value                                                                                                 }).ToArrayAsync(cancellationToken: cancellationToken);
问题2:

await (from div in Context.ILevelDataItemValue
join pc in Context.Pc
on div.PCIdequals pc.Id
join f in Context.Fund
on div.FundId equals f.Id
join di in Context.ildt
on div.ildtId equals di.Id
join p in Context.vp
on div.PeriodId equals p.Id
**join v in Context.val.Where(val => val.ValuationPeriod.PeriodQuarter == quarter && val.vp.PeriodYear == year).DefaultIfEmpty()
on pc.Id equals v.pcid into val
from v in val.DefaultIfEmpty()**
where p.PeriodYear == year && p.PeriodQuarter == quarter
select new TblA
{
pcid = pc.Id,
vid= (int?)v.Id,
fid= f.Id,
PeriodId = p.Id,
ildtid= di.Id,
Value = div.Value                                                                                                   }).ToArrayAsync(cancellationToken: cancellationToken);
除了一个连接和另一个检索所有值外,所有内容都保持不变,因此,重用此查询并在Context.valwhere v.pcid==pc.Id orderby v.Id select v.DefaultIfEmpty.Last中将这些连接语句替换为let v=from v的最佳方法是什么


我已经用**和**显示了以上两个查询中的差异。这个查询对于您的上下文来说太具体了,其他人都不容易理解

但是如果我读对了问题,您有一个很长的linq表达式,这与在另一个场景中重用非常相似,但是在另一个场景中您需要一个额外的连接

至少有两种方法可以实现您的目标

只需写出表达式的第一部分,只选择可能被重用的通用字段,不了解结果,即调用ToArray 您将有一个未执行的表达式,然后可以继续添加到该表达式中。这就是所谓的函数合成,在调用ToList或ToArray等实现结果之前,不会发生任何事情

您可以编写一个可以涵盖这两种情况的通用表达式,该表达式将谓词作为输入参数。此谓词可以用作包含第二个联接或跳过第二个联接。 不确定是否足够清楚,但这里有一个简单的例子

    var numbers = Enumerable.Range(1, 100);
    var threes = Enumerable.Range(1, 10).Select(i=> i * 3);
    var fours = Enumerable.Range(1, 10).Select(i=>i * 4);
    
    // the first query simply will output a generic results that can be reused 
    var query = from n in numbers
                join b in threes on n equals b
                select (n, b);
    
    // want to join four 
    var query2 = from a in fours 
                join q in query on a equals q.n
                select (a, q.b, q.n);
    
    query2.Dump(); // now this is realizing the results, which will combine both queries 

但是,如果您使用的是sql-to-linq,则要小心,这可能不会为您生成最佳的sql。因此,您需要进一步研究并使用直接sql,类似Dapper的方法可能会有所帮助

您必须将查询划分为两个投影

首先,选择与所需联接不相关的所有内容

var commonQuery= 从Context.ILevelDataItemValue中的div 在div.PCIdequals pc.Id上的Context.pc中加入pc 在上下文中加入f。div.FundId上的Fund等于f.Id 在div.ildtId等于di.Id的Context.ildt中连接di 在div.PeriodId上的Context.vp中加入p等于p.Id 其中p.PeriodYear==年和p.PeriodQuarter==季度 选择新的TblA { pcid=pc.Id, fid=f.Id, PeriodId=p.Id, ildtid=di.Id, 值=分区值, } 然后,您可以重用此查询来检索其他id。还更正了您的查询

var firstQuery= 来自commonQuery中的q 从Context.val.Wherev=>v.pcid==q.pcid.orderbydegeneratingv=>v.Id.Take1中的v开始 选择新的TblA { pcid=q.pcid, fid=q.fid, PeriodId=q.PeriodId, ildtid=q.ildtid, 值=q.值, vid=int?v.Id }; var fsecondQuery= 来自commonQuery中的q 在Context.val.Whereval=>val.ValuationPeriod.PeriodQuarter==quarter中加入v &&val.vp.PeriodYear==年 关于q.pcid等于v.pcid到val 从val.DefaultIfEmpty中的v开始 选择新的TblA { pcid=q.pcid, fid=q.fid, PeriodId=q.PeriodId, ildtid=q.ildtid, 值=q.值, vid=int?v.Id };
你的缩进让手机用户很难帮助你。第一个**之前的查询所表示的IQueryable可以声明一次,然后使用两次。试试看;在通过调用ToArrayAsync实现查询之前,查询只是一个简单的过程query@Flydog57Sorry对于对齐,我已经更正了它,但是在这里,我们无法重用select查询,我们再次编写相同的代码,并且必须重新进行投影,但是,您可以将需要复制到一个帮助器类中的属性分组。我们是否可以将commin查询设置为可查询的,并且只有在加入两个查询时才应该是可执行的?它已经是可查询的了。执行仅由ToList、ToArray等触发。如何重复使用您提到的投影,我们可以复制到helper类中。