商品の支払いや払い戻しを可能にするPOS(Point Of Sales)ソフトウェアを書いています。支払いまたは払い戻しの際、使用する送金平均を指定する必要があります:現金、銀行口座振込(〜=クレジットカード)、ポイントカード、バウチャーなど。
これらの送金手段は、有限で既知の値のセット(列挙型の一種)です。
トリッキーな部分は、支払いと払い戻しの両方(2つのセットは異なる場合があります)のために、これらの手段のカスタムサブセットをPOS端末に保存できる必要があることです。
例えば:
私は次のように送金手段の概念を実装することを選択します:
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で永続化するためにエンティティに対して実行する必要がある最小のリファクタリングは何ですか?
最後に、エンティティMoneyTransferMean
を2つのエンティティPaymentMean
とRefundMean
に複製することで問題を解決することにしました。
実装は似ていますが、2つのエンティティを区別することはビジネスにおいて意味があり、私にとっては最も悪いソリューションでした。
すべての共通プロパティ(フィールド)を使用して単一のエンティティMoneyTransferMeanを作成し、2つの追加フィールド(ブール値)を追加して、そのMoneyTransferMeanが支払いか払い戻しか、またはその両方かを判断しませんか? ??永続化するかどうか。
また、ID(PK)を持つ追加のエンティティを使用して実行でき、同じ追加フィールドを追加します。関係はMoneyTransferMeanと1対1になります。醜い、私は知っていますが、それはうまくいくはずです。
次に、@ DEVX75の提案に追加します。トランザクションタイプは基本的に同じ概念を示していますが、一方は+ veで、もう一方は-veです。私はおそらくブールフィールドを1つだけ追加し、支払いと返金を区別するための個別のレコードを持っています。
UIDがあり、平均としてラベル名をIDとして使用していないと仮定すると、平均の重複した名前を許可し、2つのキャッシュエントリを含めることができます。次に例を示します。
ID、ラベル、IsRefund
1、現金、偽
2、現金、真
3、バウチャー、偽
4、バウチャー、true
次に、以下を簡単に取得できます。
トランザクションタイプ = MoneyTransferMean.IsRefund? 「返金」:「お支払い」
トランザクション値 = MoneyTransferMean.IsRefund? MoneyTransfer.amount * -1:MoneyTransfer.amount
このようにして、トランザクションでMoneyTransferMean.UID = 2を参照した場合、それが現金払い戻しまたは現金払いのいずれかである可能性があるトランザクションタイプではなく、現金払い戻しであることがわかります。