同じエンティティを異なるテーブルにマッピングする


9

ドメインに関する知識

商品の支払いや払い戻しを可能にするPOS(Point Of Sales)ソフトウェアを書いています。支払いまたは払い戻しの際、使用する送金方法を指定する必要があります:現金、銀行口座振込(〜=クレジットカード)、ポイントカード、バウチャーなど。

これらの送金手段は、有限で既知の値のセット(列挙型の一種)です。

トリッキーな部分は、支払いと払い戻しの両方(2つのセットは異なる場合があります)のためにこれらの手段のカスタムサブセットをPOS端末に保存できる必要があることです。

例えば:

  • 利用可能な支払い手段:現金、EFT、ポイントカード、バウチャー
  • 利用可能な払い戻し手段:現金、バウチャー

実施の現状

私は次のように送金手段の概念を実装することを選択します:

public abstract class MoneyTransferMean : AggregateRoot
{
    public static readonly MoneyTransferMean Cash = new CashMoneyTransferMean();
    public static readonly MoneyTransferMean EFT = new EFTMoneyTransferMean();
    // and so on...

    //abstract method

    public class CashMoneyTransferMean : MoneyTransferMean
    {
        //impl of abstract method
    }

    public class EFTMoneyTransferMean : MoneyTransferMean
    {
        //impl of abstract method
    }

    //and so on...
}

「プレーン列挙」ではない理由は、これらのクラスの内部にいくつかの動作が存在するためです。また、FluentNHibernateマッピングで参照するために、内部クラスを(privateではなく)publicと宣言する必要がありました(下記参照)。

使い方

支払い手段と払い戻し手段の両方は、常にセットとしてDBに格納またはDBから取得されます。両方のセット内の一部の値が同じである場合でも、実際には2つの異なるセットです。

ユースケース1:支払い/払い戻し手段の新しいセットを定義する

  • 既存の支払い/払い戻し手段をすべて削除します
  • 新しいものを挿入する

ユースケース2:すべての支払い/払い戻し手段を取得する

  • 保存されているすべての支払い/払い戻し手段のコレクションを取得します

問題

永続性の面で現在のデザインにこだわっています。NHibernate(クラスマップを宣言するためにFluentNHibernateを使用)を使用していますが、それを有効なDBスキーマにマップする方法が見つかりません。

entity-nameを使用してクラスを複数回マッピングすることが可能であることがわかりましたが、サブクラスでそれが可能かどうかはわかりません。

私がする準備ができていないのは、それを永続化できるようにMoneyTransferMeanパブリックAPIを変更することです(たとえばbool isRefund、2つを区別するためにを追加します)。ただし、プライベート識別フィールドを追加してもかまいません。

私の現在のマッピング:

public sealed class MoneyTransferMeanMap : ClassMap<MoneyTransferMean>
{
    public MoneyTransferMeanMap()
    {
        Id(Entity.Expressions<MoneyTransferMean>.Id);
        DiscriminateSubClassesOnColumn("Type")
            .Not.Nullable();
    }
}

public sealed class CashMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.CashMoneyTransferMean>
{
    public CashMoneyTransferMeanMap()
    {
        DiscriminatorValue("Cash");
    }
}

public sealed class EFTMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.EFTMoneyTransferMean>
{
    public EFTMoneyTransferMeanMap()
    {
        DiscriminatorValue("EFT");
    }
}

//and so on...

このマッピングはコンパイルされますが、生成されるテーブルは1つだけであり、このテーブルを照会するときに支払いと払い戻しを区別できません。

MoneyTransferMean異なるテーブルとエンティティ名の両方を参照する2つのマッピングを宣言しようとしましたが、これにより例外が発生しましたDuplicate class/entity mapping MoneyTransferMean+CashMoneyTransferMean

また、サブクラスマッピングを複製しようとしましたが、上記と同じ例外につながる「親マッピング」を指定できません。

質問

現在のドメインエンティティを永続化するソリューションはありますか

そうでない場合、NHibnernateで永続化できるようにエンティティで実行する必要がある最小のリファクタリングは何ですか?


1
What I'm not ready to do is to alter the MoneyTransferMean public API to be able to persist it (for example adding a bool isRefund to differentiate between the two).: 何故なの?それはあなたの問題を解決するはずのシンプルで甘い変更です。(2はまた、重複するレコードまたはを行いますが、あなたが可能な3つの値で構成することができますFlagタイプ): 、Payment、。Refund Both2つの値が適切であれば、boolプロパティは優れています。
Amit Joshi

1
なぜそれらの支払い方法をデータベースに保存したいのですか?名前とは別に、そこの状態は何ですか?
ベルハラック

@AmitJoshiこのような小さな変更で問題が表面的に解決する可能性はありますが、ビジネスに関係のないロジックをドメインに追加することは避けたいです。
発見

@berhalak確かに、これらをデータベースに格納するのは少し不格好に見えます。ただし、これはプロジェクトの要件であり、すべての状態がデータベース内にある必要があります。
発見

回答:


0

すべての一般的なプロパティ(フィールド)を持つ単一のエンティティMoneyTransferMeanを作成し、2つのフィールド(ブール値)を追加して、そのMoneyTransferMeanが支払いか払い戻しか、またはその両方かを判断しないのはなぜですか???? 永続化するかどうか。

また、ID(PK)を持つ追加のエンティティで行うこともできます。同じ追加のフィールドを追加します。関係はMoneyTransferMeanと1対1になります。醜い、私は知っているが、それはうまくいくはずです。


ドメインに関連しない複雑さをドメインプロジェクトに追加したくない(後続のif / elseが必要なブール値を追加するなど)。また、これらのクラスを使用する人に間違いを犯させたくありません(ブール値を確認するのを忘れて、たとえば各値が払い戻しの意味であると考えて)。それはすべて明示性についてです。
発見

0

次に、@ DEVX75の提案に追加します。トランザクションタイプは基本的に同じ概念を示していますが、一方は+ veで、もう一方は-veです。私はおそらくブールフィールドを1つだけ追加し、支払いと返金を区別するための個別のレコードを持っています。

UIDがあり、平均としてラベル名をIDとして使用していないと仮定すると、平均の重複した名前を許可し、2つのキャッシュエントリを含めることができます。次に例を示します。

UID、ラベル、IsRefund

1、現金、偽

2、現金、真

3、バウチャー、偽

4、バウチャー、true

次に、以下を簡単に取得できます。

取引タイプ = MoneyTransferMean.IsRefund?「返金」:「お支払い」

取引額= MoneyTransferMean.IsRefund?MoneyTransfer.amount * -1:MoneyTransfer.amount

このようにして、トランザクションでMoneyTransferMean.UID = 2を参照した場合、それが現金払い戻しまたは現金払いのいずれかである可能性があるトランザクションタイプではなく、現金払い戻しであることがわかります。


ああバガー、あなたがパブリックAPIを編集したくない/編集できないと言ったのに気づいたところだ。申し訳ありませんが/私の答えを無視してください。ただし、おそらく同じような問題/ユースケースを持つ他の人に役立つので、そのままにしておきます。
FrugalTPH

0

最後に、エンティティMoneyTransferMeanを2つのエンティティPaymentMeanとに複製することで問題を解決することにしましたRefundMean

実装は似ていますが、2つのエンティティを区別することはビジネスにおいて意味があり、私にとっては最も悪いソリューションでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.