【问题标题】:Get all associate/composite objects inside an object (in Abstract way)获取对象内的所有关联/复合对象(以抽象方式)
【发布时间】:2012-07-13 11:56:32
【问题描述】:

商业

我有一个支付系统,可以通过 GiftCoupon、ClubMembershipCard 等方式进行支付。一次支付本身可以有多个支付组件

我有一个支付类。它具有GiftCouponPayment、ClubMembershipCardPayment、CashPayment等支付组件。每个组件类型都满足一个公共接口 IPaymentComponent。我已经使用有关现有类型的知识来实现​​它。

问题

1) 如何以抽象的方式实现这个功能——不知道所有存在的类型是什么?这意味着它需要适用于所有实现 IPaymentComponent 接口的类型。

2)如果在LINQ to SQL中无法实现,是否可以在Entity Framework中实现?

3) LINQ to SQL 在 Payment 对象中生成 GiftCouponPayment 实体时是关联/聚合还是组合?

注意:我使用 LINQ to SQL 作为 ORM。 GiftCouponPayment 和 Payment 是自动生成的类,这些对象由 ORM 创建。我通过使用部分类为这些类添加了更多功能。

注意:在数据库中,每个 PaymentComponent(例如 GiftCouponPayment)都有自己的属性(例如 CouponValue、CardValue 等)。因此 Table-Per-Hierarchy 不会很好。我们需要单独的表格。该行有解决方案吗?

注意:在此付款之前,GiftCouponPayment 已存在于数据库中。我们需要使用客户提供的 GiftCouponPaymentID 来识别 GiftCouponPayment 对象。我们只需要更新此表中的 PaymentID 列。

泄漏抽象是指任何已实现的抽象,旨在降低(或隐藏)复杂性,其中底层细节并未完全隐藏

LINQ to SQL 图

参考

  1. Entity Framework 4, inheriting vs extending?
  2. 如何选择继承策略http://blogs.msdn.com/b/alexj/archive/2009/04/15/tip-12-choosing-an-inheritance-strategy.aspx
  3. Fluent API 示例 - http://blogs.msdn.com/b/adonet/archive/2010/12/14/ef-feature-ctp5-fluent-api-samples.aspx

C# 代码

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;


    }
}

【问题讨论】:

    标签: c# entity-framework oop linq-to-sql domain-driven-design


    【解决方案1】:

    我认为您可能想暂时退出设计。我听到的是这样的:

    一笔付款由一个或多个组件组成,每个组件都可以是多种类型中的一种

    听起来你需要的是一个Payment 表,然后是一个PaymentComponent 表,它与Payment 表有一个外键关系。然后,您可以在 PaymentComponent 表上为您的各种付款方式实现继承。

    【讨论】:

    • 谢谢,但问题是 - 在数据库中,每个 PaymentComponent(例如 GiftCouponPayment)都有自己的属性(例如 CouponValue、CardValue 等)。因此,Table-Per-Hierarchy 不会很好。我们需要单独的表格。该行有解决方案吗?
    • 这将在该行中。您将拥有PaymentComponentGiftCouponPaymentComponentCash 等表,您可以将其设置为从EF 中的PaymentComponent(您将其标记为抽象)继承。然后,您可以在 PaymentComponent 表中存储常见的属性,例如 Amount
    • 谢谢。您能否设法找到一些时间用代码和数据库图详细说明答案。我认为接受它作为答案的可能性很大。
    【解决方案2】:

    您可以尝试使用 T 类型通用的抽象层或数据访问层。或者至少使方法通用。

    【讨论】:

    • 我认为,当我们引入一个新层时,它会降低生产力。我使用 ORM 来提高生产力。您认为还有其他解决方案吗?
    • 根据表的数量不需要太多,(10个表大约1-2小时),它将提供您分离数据访问的优势,因此将来会更容易如果需要更换它。
    【解决方案3】:

    你这里基本上有几个问题:

    1. 如何为支付类型建模

      假设我们想采用经典的 OOP 方式:

      您需要一个抽象的基类 Payment(或 PaymentBase)以及从它继承的各种类,例如PaymentInCash、PaymentWithCreditCard 等。

      另一种方法是将 PaymentDetails 添加到 Payment 并创建 PaymentDetails 的层次结构,如果您选择这样做,请在以下所有点中将 Payment 替换为 PaymentDetails。

      对于多种付款方式,您可以:

      一个。在 Payment
      下收集 PaymentDetails 或
      湾。创建一个名为 AggregatePayment 的类型,其中包含付款列表。

    2. 如何将付款类型映射到表格

      TPT 和 TPH 在这里都有效...

      对于 TPT,使用一张表进行付款,一张表用于每种付款。
      所有继承类型的表 PK 都应该是基类型表的 FK。
      如果您有多个层次结构,则可以在使用 EF 的情况下在第二(或任何其他)级别使用 TPT 或 TPH。

      对于 TPH,使用带有鉴别列(例如 PaymentType)的表,并将未在层次结构中的所有实体之间共享的每一列标记为可为空。不要将同一列用于不同实体中的不同属性。在 EF 中,将每个实体映射到同一个表,条件为 PaymentType = (number goes here) and (column name(s) that should not be null) is not null。

      我的建议是,如果您有许多窄类型(每个属性很少),请使用 TPH,如果您有几个宽类型,请使用 TPT。

    3. 支付算法使用哪种设计模式/代码技术

      这里有更多选择:

      一个。使用部分类并在基类上放置一个抽象的 ProcessPayment() 方法并在继承类中覆盖。

      b.使用基本的 PaymentProcessor 类和每个支付类型的特定 PaymentProcessor,例如PaymentInCashProcessor。在此方法中,您可以使用反射来加载正确的 PaymentProcessor 类型,方法是存储字典或更好的方法,使用泛型:

    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
    

    【讨论】:

      【解决方案4】:

      如果您设计 EF 模型,则可以在名为 payment 的基类上使用抽象属性。让我们继承你所有的支付类型:

      支付将具有所有通用属性,并且每种特定类型都可以有自己的属性。

      如果您有这种模型,您只需查询付款即可。

      这将返回所有继承支付类型的对象:

      
      var allPayments = objectContext.Payments;
      

      【讨论】:

      • 谢谢。但是,我不太喜欢这种方法。 PaymentComponent(例如 GifitCouponPayment)不是付款。所以做继承是不合适的。也请阅读stackoverflow.com/questions/685403/…
      • 然后做一个抽象类PaymentComponent而不是Payment。并在支付类型的支付组件中放置一个属性。
      • 在数据库中,每个 PaymentComponent(例如 GiftCouponPayment)都有自己的属性(例如 CouponValue、CardValue 等)。因此,Table-Per-Hierarchy 不会很好。我们需要单独的表格。该行有解决方案吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多