Get all associated / compound objects inside an object (in an abstract way)

Business :

I have a payment system in which payment can be made using GiftCoupon, ClubMembershipCard, etc. One payment itself may have several payment components.

Grade :

I have a payment class. It has payment components such as GiftCouponPayment, ClubMembershipCardPayment, CashPayment and so on. Each type of component complies with the general IPaymentComponent interface. I implemented it using knowledge of existing types.

Questions

1) How to implement this function in an abstract way - without knowing that all types exist? This means that it should work for all types that implement the IPaymentComponent interface.

2) If this is not possible in LINQ to SQL, is this possible in the Entity Framework?

3) Is this an association / aggregation or composition when LINQ to SQL generates GiftCouponPayment objects inside the Payment object?

Note. I am using LINQ to SQL as an ORM. GiftCouponPayment and Payment are auto-generated classes, and these objects are created by ORM. I added extra functionality for these classes using partial classes.

Note. In the database, each PaymentComponent (e.g. GiftCouponPayment) has its own properties (e.g. CouponValue, CardValue, etc.). Therefore, the table for the hierarchy will not be good . We need separate tables. Is there a solution on this line?

Note. GiftCouponPayment already exists in the database prior to this payment. We need to identify the GiftCouponPayment object using the GiftCouponPaymentID provided by the client. We just need to update the PaymentID column in this table.

Leaking abstraction refers to any implemented abstraction designed to reduce (or hide) complexity when the underlying details are not completely hidden

LINQ to SQL Chart

enter image description here

REFERENCE :

C # CODE

public interface IPaymentComponent { int MyID { get; set; } int MyValue { get; set; } int GetEffectiveValue(); } public partial class GiftCouponPayment : IPaymentComponent { public int MyID { get { return this.GiftCouponPaymentID; } set { this.GiftCouponPaymentID = value; } } public int MyValue { get { return this.CouponValue; } set { this.CouponValue = value; } } public int GetEffectiveValue() { if (this.CouponNumber < 2000) { return 0; } return this.CouponValue; } } public partial class Payment { public List<IPaymentComponent> AllPaymentComponents() { List<IPaymentComponent> allPayComps = new List<IPaymentComponent>(); List<GiftCouponPayment> giftCouponPaymentList = new List<GiftCouponPayment>(); List<CashPayment> cashPaymentList = new List<CashPayment>(); foreach (GiftCouponPayment g in this.GiftCouponPayments) { giftCouponPaymentList.Add(g); allPayComps.Add(g); } foreach (CashPayment c in this.CashPayments) { cashPaymentList.Add(c); allPayComps.Add(c); } return allPayComps; } } 
+6
source share
4 answers

I think you may need to step back from the design for a moment. I heard the following:

A payment consists of one or more components, and each component can be one of many types

It seems that you need a Payment table and then a PaymentComponent table with the ratio of the foreign key to the Payment table. Then you can implement inheritance in the PaymentComponent table for various forms of payment.

+1
source

You can try using an abstraction layer or a data access layer that will be a generic type of type T. Or at least make generic methods.

+1
source

Basically you have a few problems:

  • How to model payment types

    Suppose we want to move on to this classic OOP method:

    You need a base class, Payment (or PaymentBase), which is an abstract and different class that inherits it, for example. PaymentInCash, PaymentWithCreditCard, etc.

    An alternative would be to add PaymentDetails to the payment and create a hierarchy of PaymentDetails, if you decide to do this, replace Payment with PaymentDetails in all of the following paragraphs.

    For payments with several methods, you can:

    a. You have a collection of PaymentDetails under payment
    or
    b. Create a type called AggregatePayment that has a list of payments.

  • How to match payment types with tables

    Both TPT and TPH are valid here ...

    For TPT, use one table for payment and one table for each type of payment.
    All PK inheritance type tables must be FK in the base type table.
    If you have several levels of hierarchy, you can use TPT or TPH at the second (or any other) level if you use EF.

    For TPH, use one table with a discriminator column (for example, PaymentType) and mark each column that is not shared among all objects in the hierarchy as nullable. Do not use the same column for different properties in different objects. In EF, map each object to the same table with the condition PaymentType = (the number goes here) and (the name of the column, which must not be null) is not null.

    My recommendation is that if you have many narrow types (several properties), you can use TPH if you have several wide types for TPT.

  • What template / code design is used for the payment algorithm

    Here you have more options:

    a. Use partial classes and put the abstract ProcessPayment () method in the base class and override in the inheriting classes.

    b. Use the base class PaymentProcessor and the specific PaymentProcessor for each type of payment, for example. PaymentInCashProcessor. In this method, you can use reflection to load the correct PaymentProcessor type, either by storing dictionay, or even better using generics:

 abstract class PaymentProcessor { } abstract class PaymentProcessor<TPayment> : PaymentProcessor where TPayment : class, Payment { } class PaymentInCashProcessor : PaymentProcessor<PaymentInCash> { } // Use reflection to find types that inherits from PaymentProcessor<PaymentInCash> // create an instance of the type you found // then cast the instance to PaymentProcessor<PaymentInCash> to use 

code>

+1
source

If you create your EF model, you can use an abstract property in a base class called pay. And let it inherit all types of payments of this class:

Entity Framework model

A payment will have all common properties, and each particular type can have its own properties.

If you have such a model, you can simply request payments.

Returns all objects inheriting a payment type:

 var allPayments = objectContext.Payments; 
0
source

Source: https://habr.com/ru/post/920409/


All Articles