7

我有一个数据库关系,如下所示。域对象是基于 LINQ to SQL ORM 创建的。

付款包括现金付款和礼券付款。假设购买总金额为550,可按以下几部分支付

1 Gift Coupon Valued 300

1 Gift Coupon Valued 200

I Cash Currency Valued 50

在此处输入图像描述

我正在使用 ORM 的“InsertOnSubmit”功能插入新的付款记录。以下代码工作正常。但是,如果我公司正在引入使用信用卡的新支付组件,我需要对我的“支付”域类进行更改。如何使支付类Open for Extension 和 Closed for Changes仍然使用ORM

注意:Payment 类具有行为(例如 GetTotalAmountCollected)。我正在尝试制作“支付”类来满足 OCP。

注意:优惠券类型有特定的行为。如果 Coupon 发行日期小于 2000 年 1 月 1 日,则不应将其用于计算 Total Amount(即 CouponValue 应为零)。另请参阅使用策略模式重构代码

注意:我使用的是.Net 4.0

参考:

  1. 将 ObjectContext.AddObject 与实体框架一起使用时出错
  2. 使用策略模式重构代码
  3. 更喜欢组合而不是继承?
  4. 代码优先与模型/数据库优先
  5. 使用 Unity 的策略模式和依赖注入
  6. 委托与 OOP 的 C# 策略设计模式
  7. 如何在 C# 中使用策略模式?
  8. 使用 EF 代码优先继承:第 2 部分 - 每个类型的表 (TPT) http://weblogs.asp.net/manavi/archive/2010/12/28/inheritance-mapping-strategies-with-entity-framework-code-first -ctp5-part-2-table-per-type-tpt.aspx

C#代码:

public class PaymentAppService
{
    public RepositoryLayer.ILijosPaymentRepository Repository { get; set; }

    public void MakePayment()
    {
        DBML_Project.Payment paymentEntity = new DBML_Project.Payment();
        paymentEntity.PaymentID = 1;
        paymentEntity.PaymentType = "PurchaseP";

        DBML_Project.CashPayment cashObj = new DBML_Project.CashPayment();
        cashObj.CashPaymentID = 1;
        cashObj.CurrencyNumber = 123;
        cashObj.CurrencyValue = 100;

        DBML_Project.GiftCouponPayment giftCouponObj = new DBML_Project.GiftCouponPayment();
        giftCouponObj.GiftCouponPaymentID = 1;
        giftCouponObj.CouponValue = 200;
        giftCouponObj.CouponNumber = 124;

        paymentEntity.CashPayments = new System.Data.Linq.EntitySet<DBML_Project.CashPayment>();
        paymentEntity.CashPayments.Add(cashObj);

        paymentEntity.GiftCouponPayments = new System.Data.Linq.EntitySet<DBML_Project.GiftCouponPayment>();
        paymentEntity.GiftCouponPayments.Add(giftCouponObj);

        Repository.InsertEntity(paymentEntity);
        Repository.SubmitChanges();
    }
}

存储库:

public class LijosPaymentRepository : ILijosPaymentRepository
{
    public System.Data.Linq.DataContext MyDataContext { get; set; }

    public void InsertEntity(DBML_Project.Payment payment)
    {
        //Insert the entity
        MyDataContext.GetTable<DBML_Project.Payment>().InsertOnSubmit(payment);
    }

    public void SubmitChanges()
    {
        MyDataContext.SubmitChanges();
    }
}
4

4 回答 4

5

对于@Lijo 试图解决抽象方法的问题会更好

我认为您可以在实现您自己的 IPayment 接口的 CashPayment 类型上创建一个部分类,该接口可以在整个应用程序中使用。这个接口也可以在 CreditCardPayment 上:

例子:



public interface IPayment
{
     int Id { get; set; }
     int PaymentId { get; set; }
     //Other payment specific properties or methods
}

public partial class CashPayment : IPayment
{
    public int Id 
    {
       get { return CashPaymentId ; }
       set { CashPaymentId = value; }
    }

    //Other properties

}

public partial class CreditCardPayment : IPayment 
{
   //more code ...
}

在您的 EF 上下文中获取所有付款的内容




public partial class PaymentEntities //The name of your EF entities
{
   public IQueryable AllPayments
   {
      return this.CashPayment.Union(this.CreditCardPayment); //This is not good, but just an example. The abstract class approach would be better here.
   }

    public void InsertPayment(IPayment payment)
    {
         this.AddObject(payment.GetType().Name, payment);
    }
}

于 2012-07-11T06:29:51.900 回答
2

为每种支付类型创建新类型的附加值是什么?我可以看到“通过货币付款”和“通过凭单完成的付款”之间的区别。我可以同意有两种不同的类型来区分。

但是,为什么要区分 a CashPayment、 aCreditCardPayment等...?您是否必须根据付款类型存储额外信息?行为是否改变?

为什么不保持简单,并在常规 ' Payment' 类型中添加一个额外的属性,它充当鉴别器并为您提供付款方式的信息(通过信用卡、现金......)?

public class Payment {}

public class VoucherPayment : Payment {}

public class MoneyPayment : Payment
{
    public PaymentMode { get; set; }
}

public enum PaymentMode 
{
    Cash,
    CreditCard
}
于 2012-07-11T08:28:23.613 回答
2

也许另一种选择是在 ORM 中利用继承。这样一来,付款实体中的每种类型都没有 N 个集合,而是一个集合。您将在同一个集合中拥有所有子类型。所有这些,加起来就代表了整个付款。

也许以不同的方式命名事物会更容易。例如,让我们考虑一下Purchase的概念。购买应该有一个Payments集合。Payment可以是一个抽象类,Cash Coupon CreditCard继承自该类。

以这种方式设置模型为如何解决某些问题提供了很多可能性。您可以对所有付款一视同仁,而无需考虑不同的集合,此外还可以通过多态性和双重调度进行大量控制。

这样,如果出现新的支付类型,您的模型将保持不变,您将只有一个新的子类型。

现在大多数 ORM 支持不同的继承持久性方案,这也将有助于保持数据结构的清洁。

于 2012-07-11T06:35:26.420 回答
1

您可以使用 table-per-hierarchy (http://msdn.microsoft.com/en-us/library/bb738443) 定义您的模型,该模型使用鉴别器(即您的情况下的 PaymentType)列来指定特定风格的您正在付款。如果新的支付类型需要更多数据,那么您会感激添加列;但是,EF 在您如何定义实体以及这些实体如何映射到您的数据存储方面相当灵活。您可能拥有一组通用的列,例如 Number 和 Value,然后使用所有共享点并将具有通用名称(例如 StringValue1)的列添加到数据库中。然后,您可以将这些列映射到概念模型中更好命名的属性,这对您的域更有意义。

这基本上将您的数据库模式扁平化为一个表,但您的模型仍然是单独的类。您可以将支付类子类化为其他支付类型,而不会影响数据存储或支付类;但是,您需要修改模型以添加新的支付类型并将它们映射到适当的列。

于 2012-07-11T08:06:07.150 回答