如何编写这个LINQ来应用业务逻辑?

时间:2014-01-10 16:58:26

标签: c# linq c#-4.0

我正在尝试应用一些业务逻辑 关于在以下对象模型上使用LINQ以应用业务逻辑的问题。我相应地填充了以下对象:

public class Waiver
{
   public string Id { get; set; }
   public int Type { get; set; }
   public decimal Amount { get; set; }
}

要应用的业务逻辑:

1.。)应用订单项豁免
如果LineItem豁免[类型]是1111扣除LineItem豁免金额单位价格
如果LineItem豁免[类型]是2222扣除LineItem WaiverAmount作为百分比关闭单位价格
如果LineItem豁免[类型]是3333扣除LineItem豁免金额(线价=数量*单价)
如果LineItem豁免[类型]是4444扣除LineItem豁免金额作为离线价格百分比

2。)申请豁免
如果订单豁免[类型]为4444,则在应用LineItem豁免后扣除订单豁免金额的总订单价格 如果订单豁免[类型]为8888,则在应用LineItem豁免后扣除订单豁免金额作为百分比下单价格

实现这一目标的最佳方法是什么?

GetWaivedPrice(decimal unitPrice, int qty, IEnumerable<Waiver> waiver)

可以将GetWaivedPrice编写为单个LINQ方法,并为所有折扣类型提供适当的映射吗?

这是我想要实现的,最好是一个写得很好的LINQ方法:

private decimal GetWaivedPrice(decimal unitPrice, int qty, 
                                           IEnumerable<Waiver> waiver)
        {
            //Pseudo code shown for clarifying intent
            decimal waivedLineItemAmount = 0m;

            if waiver.Select(d => d.Type == 1111)
            //then apply the business logic on the unit price accordingly        
            if waiver.Select(d => d.Type == 2222)
            //then apply the business logic on the unit price accordingly  
            if waiver.Select(d => d.Type == 3333)
            //then apply the business logic on the unit price accordingly  

            return waivedLineItemAmount;

        }

4 个答案:

答案 0 :(得分:2)

我在这里看不到LINQ的情况。只需依次应用每个Waver

    private decimal GetWaivedPrice(decimal unitPrice, int qty, 
                                       IEnumerable<Waiver> waiver)
    {
        //Pseudo code shown for clarifying intent
        decimal waivedLineItemAmount = 0m;

        //apply all waivers
        foreach (var w in waiver) {
         switch (w.Type) { 
          case 1111:
           waivedLineItemAmout += someComputation();
           break;
          case 2222:
           waivedLineItemAmout += someComputation();
           break;
          case 3333:
           waivedLineItemAmout += someComputation();
           break;
         }
        }

        return waivedLineItemAmount;
    }

如果你坚持使用LINQ和一个纯函数式的风格,你可以用Enumerable.Aggregate来表达它,但是这里的一个简单的循环似乎很合适。

答案 1 :(得分:1)

我没有看到linq本身的需要,但可能是面向对象的设计。

我宁愿让豁免处理方法调用中的业务逻辑,例如你现在所拥有的。

public class Waiver
{
   public string Id { get; set; }
   public int Type { get; set; }
   public decimal Amount { get; set; }

   public decimal GetWaivedPrice(decimal unitPrice, int qty) { ... }

}

通过这样做,它可以促进任何未来的linq预测或操作,例如这种分组,当然可以集中业务逻辑,以便将来维护。

var groupedResult = myWaivers.Select(wv => new
    {
       Type = wv.Type,
       WaivedPrice = wv.GetWaivedPrice( unitPrice, qty)
    } )
                             .GroupBy(wv => wv.Type);

答案 2 :(得分:1)

怎么样:

private static Dictionary<int, Func<decimal, int, Waiver, decimal>> _logic
    = new Dictionary<int, Func<decimal, int, Waiver, decimal>>() {
        { 2222, (a, q, w) => a + w.Amount },
        { 3333, (a, q, w) => a + w.Amount },
        { 3333, (a, q, w) => a + w.Amount }
    };

private static decimal GetWaivedPrice(decimal unitPrice, int qty, 
                                   IEnumerable<Waiver> waiver)
{
    return waiver.Aggregate(0m, (a, s) => _logic[s.Type](a, qty, s), a => a);
}

当然,您必须使用折扣逻辑更新_logic字典才能使其正常工作。

答案 3 :(得分:1)

业务规则被隔离成单独的问题(演绎和策略),现在它已经非常LINQ了!

// Create a data structure to model the deductions themselves
public class LineItemDeduction
{
    public decimal UnitPriceAmount { get; set; }
    public decimal UnitPricePercentage { get; set; }
    public decimal LinePriceAmount { get; set; }
    public decimal LinePricePercentage { get; set; }

    // Assumed that waivers are distinct and are not composed together, only applied on the listed price.
    public decimal CalculateWaivedPrice(decimal unitPrice, int qty)
    {
        return ((unitPrice - UnitPriceAmount - (unitPrice * UnitPricePercentage)) * qty) - LinePriceAmount - (unitPrice * qty * LinePricePercentage);
    }
}

// Calculate the deductions
private LineItemDeduction CalculateLineItemDeductionStrategy(LineItemDeduction deduction, Waiver waiver)
{
    switch (waiver.Type) { 
      case 1111:
       deduction.UnitPriceAmount += waiver.Amount;
       break;
      case 2222:
       deduction.UnitPricePercentage += waiver.Amount;
       break;
      case 3333:
       deduction.LinePriceAmount += waiver.Amount;
       break;
      case 4444:
       deduction.LinePricePercentage += waiver.Amount;
       break;
     }

     return deduction;
}

// Extension method only for LineItem but it's the same principle for order waivers
public static decimal GetWaivedPrice(this IEnumerable<Waiver> waivers, decimal unitPrice, int qty, Func<LineItemDeduction, Waiver, LineItemDeduction> deductionStrategy)
{
    return waivers.Aggregate(
        new LineItemDeduction(),
        deductionStrategy,
        d => d.CalculateWaivedPrice(unitPrice, qty)
    );
}

// Now to get the waived price
var waivedPrice = waivers.GetWaivedPrice(unitPrice, qty, CalculateLineItemDeductionStrategy);