如何优化此LINQ查询以仅执行单个SQL命令?

时间:2010-06-22 17:00:57

标签: c# linq linq-to-sql

我正在使用Linq-To-Sql来填充我的业务层。以下是我正在处理的查询的片段:

fund.FundEntities = fundGroup.tFunds
    .Select(fe =>
    {
        var fundEntity = new FundEntity()
        {
            BankAccount = null,
            CloseDate = fe.closeDate ?? new DateTime(),
            Commitment = fe.commitment ?? 0,
            CommitmentEndDate = fe.closeDate ?? new DateTime(),
            Fund = fund
        };
        fundEntity.CapitalCalls = fe.tCapitalCalls
            .Select(cc =>
            {
                return new CapitalCall()
                {
                    Amount = cc.agrAmount ?? 0,
                    FundEntity = fundEntity
                };
            }
             );
        return fundEntity;
    });

当我运行此代码时,它会在运行时为各个CapitalCalls执行查询。无论如何,我可以重新设计这个以保持相同的业务对象结构(IE-与基金的关系 - > FundEntity - >业务对象中的CapitalCall),但一次加载完整的表?理想情况下,会有一个带有大量连接的SQL查询,这会产生一个完全填充的基金。

4 个答案:

答案 0 :(得分:3)

问题的解决方案是同时执行多个查询并将结果数据绑定在一起。虽然LINQ to SQL可以执行此操作,但它本身不支持此类功能。

PLINQO是一个开源替代品,它是LINQ to SQL的替代品,它为框架增加了额外的功能。特别是,您会对批量查询和未来查询感兴趣。

http://www.plinqo.com

上查看

希望有所帮助! -Tom DuPont(PLINQO开发团队成员)

答案 1 :(得分:1)

var fund = GetFund();
var fundGroup = GetFundGroup();
var dataContest = GetDataContext();


List<int> feIds = fundGroup.tFunds.Select(fe => fe.FundEntityId).ToList();

 //before: iterate through local collection fundGroup.tFunds
 //  and issue one CapitalCall query per fundEntity.
 //after: send all the fundEntityIds into the database in one query
 //  that also fetches related CapitalCalls.
var query =
  from fe in dataContext.tFunds
  where feIds.Contains(fe.FundEntityId))
  let capitalCalls = fe.tCapitalCalls
  select new {FundEntity = fe, CapitalCalls = capitalCalls.ToList() };

foreach(var record in query)
{
  FundEntity fundEntity = new FundEntity()
  {
    CloseDate = record.fe.closeDate ?? new DateTime(),
    ...
  }
  fundEntity.CapitalCalls = ...
}

答案 2 :(得分:0)

对我而言似乎是你倒退而不是前锋。你正试图去基金 - &gt; FundEntity - &gt; CapitalCalls,但随后试图给每个人一个对其容器的引用。

您可以考虑对数据库进行更简单的查询,在其上调用ToList,然后使用Linq to Objects将其重新投影到所需的结构中。

您还可以考虑以其他方式编写查询并使用group by。从概念上讲,您将获得资本要求,并按基金实体对其进行分组,然后按基金对这些进行分组。

如果您认为没有容器引用就可以生存,那么您拥有的查询可以表示如下,该查询应该在一个查询中使用连接。

fund.FundEntities = fundGroup.tFunds
.Select(fe =>
{
    new FundEntity
    {
        BankAccount = null,
        CloseDate = fe.closeDate ?? new DateTime(),
        Commitment = fe.commitment ?? 0,
        CommitmentEndDate = fe.closeDate ?? new DateTime(),
        CapitalCalls = fe.tCapitalCalls
        .Select(cc =>
        {
            new CapitalCall
            {
                Amount = cc.agrAmount ?? 0
            };
        }
    }
});

答案 3 :(得分:0)

我会选择像SteadyEddi这样的东西(我包含了FundEntity),但我认为你可以像你想要的那样表达它(或者像SteadyEddi那样的非LINQ方式):

fund.FundEntities =
from fe in fundGroup.tFunds
select new FundEntity()
{
    BackAccount = null,
    CloseDate = fe.closeDate ?? new DateTime(),
    Commitment = fe.commitment ?? 0,
    CommitmentEndDate = fe.closeDate ?? new DateTime(),
    Fund = fund,
    CapitalCalls = from cc in fe.tCapitalCalls
                   select new CapitalCall()
                   {
                       Amount = cc.agrAmount ?? 0,
                       FundEntity = fundEntity
                   }
}

如果没有,我认为你的数据库映射正在发生的事情,无论如何都应该重新考虑:)错误的名称等等.DateDate == CommitmentEndDate。您的代码的问题可能是您自己构建CapitalCalls,因此LINQ-TO-SQL可能无法正确解码表达式树。但同样,我显然没有测试我的代码,所以我不知道我的代码是否有效。