Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
69 views
in Technique[技术] by (71.8m points)

c# - Making Entity Class Closed for Changes

I have a database relationship as shown below. The domain objects are created based on LINQ to SQL ORM.

A payment comprises of Cash Payment and Gift Coupon Payments. Suppose the total amount of purchase is 550. It can be paid as following components

1 Gift Coupon Valued 300

1 Gift Coupon Valued 200

I Cash Currency Valued 50

enter image description here

I am inserting new payment records using the “InsertOnSubmit” function of ORM. The following code is working fine. However, if I the company is introducing a new payment component using credit card, I need to make changes to my “Payment” domain class. How do I make the payment class Open for Extension and Closed for Changes still using ORM?

Note: The Payment class has behaviors (E.g. GetTotalAmountCollected). I am trying to make the "Payment" class to satisfy OCP.

Note: There is a specific behavior for Coupon type. Is the Coupon issued date is less than 1/1/2000, it should not be used in calculation for Total Amount (i.e, CouponValue should be zero). Refer Refactoring code using Strategy Pattern also.

Note: I am using .Net 4.0

Reference:

  1. Getting an error when using ObjectContext.AddObject with Entity Framework
  2. Refactoring code using Strategy Pattern
  3. Prefer composition over inheritance?
  4. Code-first vs Model/Database-first
  5. Strategy Pattern and Dependency Injection using Unity
  6. C# Strategy Design Pattern by Delegate vs OOP
  7. How to use the Strategy Pattern with C#?
  8. Inheritance with EF Code First: Part 2 – Table per Type (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# Code:

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();
    }
}

Repository:

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();
    }
}
Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For the problem that @Lijo tries to solve the abstract approach would be better

I think you can make a partial class on the CashPayment type that implements your own IPayment interface, which can be used through the whole application. This interface can then also be on CreditCardPayment:

Example:



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 ...
}

Something on your EF context to get all payments




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);
    }
}


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...