6

事業内容:

GiftCoupon、ClubMembershipCard などを使用して支払いを行うことができる支払いシステムがあります。1 つの支払い自体に複数の支払いコンポーネントを含めることができます。

クラス:

私は支払いクラスを持っています。GiftCouponPayment、ClubMembershipCardPayment、CashPayment などの支払いコンポーネントがあります。各コンポーネント タイプは、共通のインターフェイス IPaymentComponent を満たします。既存の型に関する知識を使用して実装しました。

質問

1)存在するすべての型を知らずに、この関数を抽象的な方法で実装する方法は? つまり、IPaymentComponent インターフェイスを実装するすべてのタイプで機能する必要があります。

2) LINQ to SQL で実現できない場合、Entity Framework で実現できますか?

3) LINQ to SQLが Payment オブジェクト内で GiftCouponPayment エンティティを生成するとき、それは関連付け/集約または構成ですか?

注: ORM として LINQ to SQL を使用しています。GiftCouponPayment と Payment は自動生成されたクラスであり、これらのオブジェクトは ORM によって作成されます。部分クラスを使用して、これらのクラスにさらに機能を追加しました。

注: データベースでは、各 PaymentComponent (GiftCouponPayment など) には独自のプロパティ (CouponValue、CardValue など) があります。したがって、Table-Per-Hierarchy は適切ではありません。別々のテーブルが必要です。その行に解決策はありますか?

注: GiftCouponPayment は、この支払いの前にデータベースに既に存在します。顧客から提供された GiftCouponPaymentID を使用して、GiftCouponPayment オブジェクトを識別する必要があります。このテーブルの PaymentID 列を更新するだけです。

漏れやすい抽象化とは、複雑さを軽減 (または非表示) することを目的として実装された抽象化を指し、基礎となる詳細が完全には隠されていません。

LINQ to SQL ダイアグラム

ここに画像の説明を入力

参考

  1. Entity Framework 4、継承と拡張?
  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;


    }
}
4

4 に答える 4

1

タイプTのジェネリックとなる抽象化レイヤーまたはデータアクセスレイヤーの使用を試みることができます。または、少なくともメソッドをジェネリックにします。

于 2012-07-13T11:59:03.400 に答える
1

ここには基本的にいくつかの問題があります。

  1. 支払いタイプをモデル化する方法

    これを古典的なOOPの方法で進めたいとしましょう:

    抽象クラスである基本クラス Payment (または PaymentBase) と、そこから継承するさまざまなクラス (PaymentInCash、PaymentWithCreditCard など) が必要です。

    別の方法として、Payment に PaymentDetails を追加し、PaymentDetails の階層を作成することもできます。これを行う場合は、次のすべてのポイントで Payments を PaymentDetails に置き換えます。

    複数の方法による支払いの場合、次のいずれかを行うことができます。

    a.
    Paymentまたは
    bの下に PaymentDetails のコレクションがあります。Payments のリストを持つ AggregatePayment というタイプを作成します。

  2. 支払いタイプをテーブルにマップする方法

    ここではTPTとTPHの両方が有効です...

    TPTでは、支払い用に 1 つのテーブルを使用し、支払いの種類ごとに 1 つのテーブルを使用します。
    継承する型のテーブル PK はすべて、基本型のテーブルの FK である必要があります。
    階層に複数のレベルがある場合、EF を使用している場合は、2 番目のレベル (またはその他のレベル) で TPT または TPH を使用できます。

    TPHの場合、識別子列 (PaymentType など) を持つ 1 つのテーブルを使用し、階層内のすべてのエンティティ間で共有されていない各列を null 許容としてマークします。異なるエンティティの異なるプロパティに同じ列を使用しないでください。EF では、PaymentType = (数値がここに入る) および (null であってはならない列名) が null でないという条件で、各エンティティを同じテーブルにマップします。

    私のお勧めは、ナロー タイプが多数ある場合 (それぞれのプロパティが少ない場合) は TPH を使用し、ワイド タイプが少ない場合は TPT を使用することです。

  3. 支払いアルゴリズムに使用する設計パターン/コード手法

    ここにはさらにオプションがあります:

    a. 部分クラスを使用し、抽象 ProcessPayment() メソッドを基本クラスに置き、継承クラスでオーバーライドします。

    b. 基本 PaymentProcessor クラスと、PaymentInCashProcessor などの支払いタイプごとの特定の PaymentProcessor を使用します。このメソッドでは、リフレクションを使用して、ディクショナリを保存するか、ジェネリックを使用して正しい 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

于 2012-07-13T16:26:45.900 に答える
1

ちょっとデザインから離れたほうがいいと思います。私が聞いたのはこれです:

支払いは 1 つ以上のコンポーネントで構成され、各コンポーネントはさまざまなタイプのいずれかになります。

必要なように聞こえるのは、Paymentテーブルと、PaymentComponentテーブルへの外部キー関係を持つPaymentテーブルです。PaymentComponent次に、さまざまな支払い方法のテーブルに継承を実装できます。

于 2012-07-13T14:02:46.557 に答える
0

EFモデルを設計する場合は、支払いと呼ばれる基本クラスの抽象プロパティを使用できます。そして、そのクラスのすべての支払いタイプを継承しましょう。

EntityFrameworkモデル

支払いにはすべての共通のプロパティがあり、すべての特定のタイプには独自のプロパティがあります。

この種のモデルがある場合は、支払いを照会するだけです。

これにより、支払いタイプを継承するすべてのオブジェクトが返されます。


var allPayments = objectContext.Payments;
于 2012-07-13T13:38:59.550 に答える