【问题标题】:Combine two entities合并两个实体
【发布时间】:2018-10-04 17:54:15
【问题描述】:

我有一个使用 EF Core 的 MVC 项目。我创建了虚拟 Dto 来从我的数据库中选择逻辑查询。现在我被卡住了,我有一个方法

    public IEnumerable<FinalEntity> getTest(int month,int year)
    {
        var dataFromSpecialPayments = _sabresRepository.GetBrokerMonthlyCommissionSpecialPayments(month, year);
        var dataFromTotals = _sabresRepository.GetBrokerMonthlyCommissionTotals(month, year);

这两个变量包含了逻辑和聚合后的数据,它们的ID之间有1:1的关系(虽然另一个表中有很多没有匹配的记录,所以需要完全加入)。现在我需要将这两个实体加入到我的最终实体中。这些是 Dto 的:

public class BrokerMonthlyCommission_Total_AggDto : DtoBase
{
    public int BrokerId { get; set; }
    public decimal TotalCommissionAmountBruto { get; set; }
    public decimal TotalCommissionAmountNeto { get; set; }
    public decimal TotalDistributingFeeParticipation { get; set; }
    public string BrokerName { get; set; }
    public int? CommissionPaymentStatusPl { get; set; }
    public int? MinCommissionForPayment { get; set; }
} 

public class BrokerMonthlyCommission_SpecialPayment_AggDto
{
    public int BrokerId { get; set; }
    public decimal TotalSpecialPayments { get; set; }
    public int PaymentStatus { get; set; }
}

public class FinalDto : DtoBase
{
    public int BrokerId { get; set; }
    public decimal TotalCommissionAmountBruto { get; set; }
    public decimal TotalCommissionAmountNeto { get; set; }
    public decimal TotalDistributingFeeParticipation { get; set; }
    public string BrokerName { get; set; }
    public int? CommissionPaymentStatusPl { get; set; }
    public int? MinCommissionForPayment { get; set; }
    public decimal TotalSpecialPayments { get; set; }
    public int PaymentStatus { get; set; }
} 

我该怎么做?我知道我可能可以使用 foreach 循环运行并遍历每条记录,但我正在寻找更好的解决方案

【问题讨论】:

  • 你试过什么?循环一个集合,在另一个集合中找到匹配的 DTO,然后投影到 new FinalDto { X = x.X, Y = y.Y, ...}?如果您想使用数据库连接来解决此问题,您可能不得不放弃存储库方法或使用返回所需对象的方法扩展任一存储库。
  • 我想过在数据库里做,但是在join之前每个表都要聚合(这是方法做的),所以linq查询对我来说变得很复杂
  • @Yossi,我编辑了我的答案以使用左连接和右连接的联合。

标签: c# entity-framework


【解决方案1】:

此查询使用左连接和右连接的并集。 CommissionTotal 的 BrokerId 为 1、2 和 3。commissionSpecial 的 BrokerId 为 1、2 和 4。结果是 BrokerId 的 1、2、3 和 4。

void Main()
{
    var commissionTotal = new []
    {
        new BrokerMonthlyCommission_Total_AggDto { BrokerId = 1, TotalCommissionAmountBruto = 1000, TotalCommissionAmountNeto = 1000,
            TotalDistributingFeeParticipation = 1000, BrokerName = "B1", CommissionPaymentStatusPl = 1, MinCommissionForPayment = 2 },
        new BrokerMonthlyCommission_Total_AggDto { BrokerId = 2, TotalCommissionAmountBruto = 2000, TotalCommissionAmountNeto = 2000,
            TotalDistributingFeeParticipation = 2000, BrokerName = "B2", CommissionPaymentStatusPl = 1, MinCommissionForPayment = 2 },
        new BrokerMonthlyCommission_Total_AggDto { BrokerId = 3, TotalCommissionAmountBruto = 3000, TotalCommissionAmountNeto = 3000,
            TotalDistributingFeeParticipation = 2000, BrokerName = "B3", CommissionPaymentStatusPl = 1, MinCommissionForPayment = 2 }
    };

    var commissionSpecial = new []
    {
        new BrokerMonthlyCommission_SpecialPayment_AggDto { BrokerId = 1, TotalSpecialPayments = 100, PaymentStatus = 1 },
        new BrokerMonthlyCommission_SpecialPayment_AggDto { BrokerId = 2, TotalSpecialPayments = 300, PaymentStatus = 2 },
        new BrokerMonthlyCommission_SpecialPayment_AggDto { BrokerId = 4, TotalSpecialPayments = 900, PaymentStatus = 4 }
    };

    var leftJoin =
        from ct in commissionTotal
        join cs in commissionSpecial on ct.BrokerId equals cs.BrokerId into temp
        from cs in temp.DefaultIfEmpty(new BrokerMonthlyCommission_SpecialPayment_AggDto
        {
            BrokerId = ct.BrokerId,
            TotalSpecialPayments = default(decimal),
            PaymentStatus = default(int)
        })
        select new {CT = ct, CS = cs};

    var rightJoin =
        from cs in commissionSpecial
        join ct in commissionTotal on cs.BrokerId equals ct.BrokerId into temp
        from ct in temp.DefaultIfEmpty(new BrokerMonthlyCommission_Total_AggDto
        {
            BrokerId = cs.BrokerId,
            TotalCommissionAmountBruto = default(decimal),
            TotalCommissionAmountNeto = default(decimal),
            TotalDistributingFeeParticipation = default(decimal),
            BrokerName = default(string),
            CommissionPaymentStatusPl = default(int?),
            MinCommissionForPayment = default(int?)
        })
        select new {CT = ct, CS = cs};

    var final = leftJoin.Union(rightJoin).Select(x => new FinalDto
    {
        BrokerId = x.CT.BrokerId,
        TotalCommissionAmountBruto = x.CT.TotalCommissionAmountBruto,
        TotalCommissionAmountNeto = x.CT.TotalCommissionAmountNeto,
        TotalDistributingFeeParticipation = x.CT.TotalDistributingFeeParticipation,
        BrokerName = x.CT.BrokerName,
        CommissionPaymentStatusPl = x.CT.CommissionPaymentStatusPl,
        MinCommissionForPayment = x.CT.MinCommissionForPayment,
        TotalSpecialPayments = x.CS.TotalSpecialPayments,
        PaymentStatus = x.CS.PaymentStatus
    });
    final.Dump(); // remove this line if not in LinqPad
}

public class BrokerMonthlyCommission_Total_AggDto
{
    public int BrokerId { get; set; }
    public decimal TotalCommissionAmountBruto { get; set; }
    public decimal TotalCommissionAmountNeto { get; set; }
    public decimal TotalDistributingFeeParticipation { get; set; }
    public string BrokerName { get; set; }
    public int? CommissionPaymentStatusPl { get; set; }
    public int? MinCommissionForPayment { get; set; }
}

public class BrokerMonthlyCommission_SpecialPayment_AggDto
{
    public int BrokerId { get; set; }
    public decimal TotalSpecialPayments { get; set; }
    public int PaymentStatus { get; set; }
}

public class FinalDto
{
    public int BrokerId { get; set; }
    public decimal TotalCommissionAmountBruto { get; set; }
    public decimal TotalCommissionAmountNeto { get; set; }
    public decimal TotalDistributingFeeParticipation { get; set; }
    public string BrokerName { get; set; }
    public int? CommissionPaymentStatusPl { get; set; }
    public int? MinCommissionForPayment { get; set; }
    public decimal TotalSpecialPayments { get; set; }
    public int PaymentStatus { get; set; }
}

LinqPad 中的结果:

注意:

  1. 我从DtoBase 中删除了继承,因为我没有那个类。
  2. 对于 BrokerId = 4,BrokerName 为空,因为它是来自 BrokerMonthlyCommission_SpecialPayment_AggDto 的右连接,并且没有 BrokerName 属性。

【讨论】:

  • 谢谢,我会检查并报告
  • @Yossi,我对更紧凑的代码做了一个小改进。感谢您接受我的回答。
  • 是的,我自己修好了 :)
【解决方案2】:

您基本上可以使用 System.Linq 库中的 select 来实现这一点,并手动将您的类型转换为 FinalDto。

var dataFromSpecialPayments = _sabresRepository.GetBrokerMonthlyCommissionSpecialPayments(month, year)
    .Select(x => new FinalDto
    {
        BrokerId = x.BrokerId,
        //assign other properties
    });

【讨论】:

    【解决方案3】:

    使用Linq Join?

    dataFromSpecialPayments.Join(dataFromTotals,
      sp => sp.Id,
      ft => ft.Id,
      (specialPayment, fromTotal) => new FinalDto 
      {
        BrokerId = specialPayment.BrokerId,
        /// etc
      })
      .ToList()
    

    【讨论】:

    • 顺便说一句,这是什么连接?内?因为我需要一个完整的外部联接
    • 谢谢,这几乎可以完美运行,我只需要一个外连接而不是普通连接。我该怎么做?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多