简体   繁体   English

我的 Linq 查询是否在 EF Core 3.1 中具有最佳和高性能?

[英]Is my Linq Query Optimal and High performance in EF Core 3.1?

can i remove vg.First().Voucher?我可以删除 vg.First().Voucher 吗? and replace the beter code?并替换更好的代码? what is the optimal and best practice?什么是最佳和最佳实践? is convertable this code to another method?可以将此代码转换为另一种方法吗? like chain method?像链式方法?

        var query = from v in _journalLineRepository.TableNoTracking
                .Include(j => j.Voucher).AsEnumerable()
                    group v by v.AccountId into vg
                    select new // <-- temporary projection with group by fields needed
                    {
                        AccountId = vg.Key,
                        Credit = vg.Sum(v => v.Credit),
                        Debit = vg.Sum(v => v.Debit),
                        Voucher = vg.First().Voucher

                    } into vg
                    join p in _partyRepository.TableNoTracking.Include(p => p.PartyPhones).AsEnumerable() on vg.AccountId equals p.AccountId // <-- additional join(s)
                    select new PartyDeptorAndCreditorViewModel
                    {



                        PartyId = p.Id,
                        FullName = p.FullName,
                        PhoneNo = p.PartyPhones.FirstOrDefault(p => p.IsActive)?.Phone,
                        ProjectId = vg.Voucher.ProjectId,
                        AccountId = vg.AccountId.Value,
                        Creditor = vg.Credit,
                        Deptor = vg.Debit,
                        Balance = vg.Credit - vg.Debit,
                        VoucherDate = vg.Voucher.VoucherDate,
                        VoucherRegisterDate = vg.Voucher.VoucherDate,
                        BalanceType =
                            vg.Debit > vg.Credit ? AccountingComplexEnum.ShowPartyBalanceParamSearch.Deptor.ToDisplay(DisplayProperty.Name) :
                            vg.Debit < vg.Credit ? AccountingComplexEnum.ShowPartyBalanceParamSearch.Creditor.ToDisplay(DisplayProperty.Name) :
                             AccountingComplexEnum.ShowPartyBalanceParamSearch.ZeroBalance.ToDisplay(DisplayProperty.Name),

                    };

I'd certainly be looking at the SQL query generated.我肯定会查看生成的 SQL 查询。 At face value I see a few warning flags that it may not be composing a query but possibly pre-executing to in-memory processing which would be inefficient.从表面上看,我看到一些警告标志,它可能不是在编写查询,而是可能预先执行到内存中的处理,这将是低效的。 It would firstly depend on what these .TableNoTracking methods/properties return, and the use of .AsEnumerable on the eager load joins.它首先取决于这些.TableNoTracking方法/属性返回什么,以及在急切加载连接上使用.AsEnumerable

Firstly, when projecting with Select , eager load joins ( .Include ) are not necessary.首先,使用Select进行投影时,不需要急切加载连接( .Include )。 The projections will take care of the joins for you, provided it is projecting down to SQL.投影将为您处理连接,只要它向下投影到 SQL。 If you take out the .Include().AsEnumerable() calls and your query still works then it is likely projecting down to SQL.如果您取出.Include().AsEnumerable()调用并且您的查询仍然有效,那么它可能会投射到 SQL。 If it is no longer working then it's processing in memory and not efficiently.如果它不再工作,那么它在 memory 中处理并且效率不高。

Edit: Nope, the inner projection won't resolve: Regarding the .Voucher , your final projection is using 2 fields from this entity, so it stands you could replace this in the initial projection: 编辑:不,内部投影无法解决: 关于 .Voucher ,您的最终投影使用该实体的 2 个字段,因此您可以在初始投影中替换它:

 select new // <-- temporary projection with group by fields needed { AccountId = vg.Key, Credit = vg.Sum(v => v.Credit), Debit = vg.Sum(v => v.Debit), Voucher = vg.Select(v => new { v.ProjectId, v.VoucherDate }).First() } into vg

When it comes to transformations like this:当涉及到这样的转换时:

BalanceType = vg.Debit > vg.Credit 
    ?        AccountingComplexEnum.ShowPartyBalanceParamSearch.Deptor.ToDisplay(DisplayProperty.Name) 
    : vg.Debit < vg.Credit 
        ? AccountingComplexEnum.ShowPartyBalanceParamSearch.Creditor.ToDisplay(DisplayProperty.Name) 
        : AccountingComplexEnum.ShowPartyBalanceParamSearch.ZeroBalance.ToDisplay(DisplayProperty.Name),

... inside a projection, this sends off warning flags as Linq2EF needs to compose projections down to SQL so methods/extensions like ToDisplay won't be understood. ...在一个投影中,这会发出警告标志,因为 Linq2EF 需要将投影组合到 SQL 因此无法理解像ToDisplay这样的方法/扩展。 Instead, since this is based solely on the Credit/Debit amounts, I'd move this to be computed by the property in the view model:相反,由于这仅基于贷方/借方金额,因此我将其移动到由视图 model 中的属性计算:

select new PartyDeptorAndCreditorViewModel
{
    PartyId = p.Id,
    FullName = p.FullName,
    PhoneNo = p.PartyPhones
        .Where(p => p.IsActive)
        .Select(p => p.Phone)
        .FirstOrDefault(),
    ProjectId = vg.Voucher.ProjectId,
    AccountId = vg.AccountId.Value,
    Creditor = vg.Credit,
    Deptor = vg.Debit,
    Balance = vg.Credit - vg.Debit,
    VoucherDate = vg.Voucher.VoucherDate,
    VoucherRegisterDate = vg.Voucher.VoucherDate
};

Then in the view model:然后在model视图中:

[Serializable]
public class PartyDebtorAndCreditorViewModel
{
    // ... 
    public decimal Balance { get; set; }

    public string BalanceType 
    {
        get 
        { 
             return Balance < 0 
                ? AccountingComplexEnum.ShowPartyBalanceParamSearch.Deptor.ToDisplay(DisplayProperty.Name) 
                : Balance > 0
                    ? AccountingComplexEnum.ShowPartyBalanceParamSearch.Creditor.ToDisplay(DisplayProperty.Name) 
                    : AccountingComplexEnum.ShowPartyBalanceParamSearch.ZeroBalance.ToDisplay(DisplayProperty.Name);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM