Ein bisschen Domainwissen
Ich schreibe eine POS-Software (Point Of Sales), mit der Waren bezahlt oder erstattet werden können. Bei der Zahlung oder Rückerstattung muss angegeben werden, welche Geldüberweisung verwendet werden soll: Bargeld, Überweisung (~ = Kreditkarte), Kundenkarte, Gutschein usw.
Diese Geldtransfermittel sind eine endliche und bekannte Menge von Werten (eine Art Aufzählung).
Der schwierige Teil ist, dass ich in der Lage sein muss, eine benutzerdefinierte Teilmenge dieser Mittel sowohl für Zahlungen als auch für Rückerstattungen (die beiden Sätze können unterschiedlich sein) auf dem POS-Terminal zu speichern.
Zum Beispiel:
- Verfügbare Zahlungsmittel: Bargeld, Überweisung, Kundenkarte, Gutschein
- Verfügbare Rückerstattung bedeutet: Bargeld, Gutschein
Aktueller Stand der Umsetzung
Ich entscheide mich, das Konzept des Geldtransfermittels wie folgt umzusetzen:
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...
}
Der Grund, warum es sich nicht um eine "einfache Aufzählung" handelt, ist, dass es ein Verhalten innerhalb dieser Klassen gibt. Ich musste auch innere Klassen öffentlich (statt privat) deklarieren, um sie in der FluentNHibernate-Zuordnung zu referenzieren (siehe unten).
Wie es verwendet wird
Sowohl das Zahlungs- als auch das Rückerstattungsmittel werden immer als Satz in / aus der Datenbank gespeichert oder abgerufen. Es handelt sich tatsächlich um zwei unterschiedliche Mengen, obwohl einige Werte in beiden Mengen möglicherweise gleich sind.
Anwendungsfall 1: Definieren Sie einen neuen Satz von Zahlungs- / Rückerstattungsmitteln
- Löschen Sie alle vorhandenen Zahlungs- / Rückerstattungsmittel
- Fügen Sie die neuen ein
Anwendungsfall 2: Rufen Sie alle Zahlungs- / Rückerstattungsmittel ab
- Holen Sie sich eine Sammlung aller gespeicherten Zahlungs- / Rückerstattungsmittel
Problem
Ich bleibe bei meinem aktuellen Design in Bezug auf den Persistenzaspekt. Ich verwende NHibernate (mit FluentNHibernate zum Deklarieren von Klassenzuordnungen) und kann keine Möglichkeit finden, es einem gültigen DB-Schema zuzuordnen.
Ich habe festgestellt, dass es möglich ist, eine Klasse mehrmals mit dem Entitätsnamen zuzuordnen, bin mir jedoch nicht sicher, ob dies mit Unterklassen möglich ist.
Ich bin nicht bereit, die öffentliche MoneyTransferMean-API so zu ändern, dass sie beibehalten werden kann (z. B. Hinzufügen eines bool isRefund
, um zwischen beiden zu unterscheiden). Das Hinzufügen eines privaten Diskriminatorfeldes oder so ist jedoch in Ordnung.
Mein aktuelles Mapping:
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...
Diese Zuordnung wird kompiliert, es wird jedoch nur 1 Tabelle erstellt, und ich kann bei der Abfrage dieser Tabelle nicht zwischen Zahlung / Rückerstattung unterscheiden.
Ich habe versucht, zwei Zuordnungen zu deklarieren, die sowohl MoneyTransferMean
auf unterschiedliche Tabellen als auch auf unterschiedliche Entitätsnamen verweisen. Dies führt mich jedoch zu einer Ausnahme Duplicate class/entity mapping MoneyTransferMean+CashMoneyTransferMean
.
Ich habe auch versucht, Zuordnungen von Unterklassen zu duplizieren, kann jedoch keine "übergeordnete Zuordnung" angeben, die mich zu derselben Ausnahme wie oben führt.
Frage
Gibt es eine Lösung, um meine aktuellen Domänenentitäten beizubehalten?
Wenn nicht, was wäre der kleinste Refaktor, den ich für meine Entitäten ausführen muss, um sie mit NHibnernate dauerhaft zu machen?
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).
: Warum nicht? Es ist eine einfache und süße Veränderung, die Ihr Problem lösen sollte. Sie können mit drei möglichen Werte bilden (obwohl zwei auch mit doppelten Datensätzen oder tunFlag
Typ):Payment
,Refund
,Both
. Wenn zwei Werte für Sie zutreffen, ist diebool
Eigenschaft großartig.Antworten:
Warum erstellen Sie nicht eine einzelne Entität MoneyTransferMean mit allen allgemeinen Eigenschaften (Feldern) und fügen einfach zwei zusätzliche Felder (Boolesche Werte) hinzu, um festzustellen, ob es sich bei MoneyTransferMean entweder um Zahlung oder Rückerstattung oder um beides handelt? Behalte es bei oder nicht.
Es kann auch mit einer zusätzlichen Entität mit ID (PK) durchgeführt werden. Fügen Sie dieselben zusätzlichen Felder hinzu. Die Beziehung wäre 1: 1 mit MoneyTransferMean. Hässlich, ich weiß, aber es sollte funktionieren.
quelle
Ich würde dem, was @ DEVX75 vorschlug, zustimmen und hinzufügen, dass Ihre Transaktionstypen im Wesentlichen dasselbe Konzept beschreiben, obwohl einer + ve ist, während der andere -ve ist. Ich würde wahrscheinlich nur ein boolesches Feld hinzufügen und separate Datensätze haben, um Rückerstattungen von Zahlungen zu unterscheiden.
Angenommen, Sie haben eine UID und verwenden nicht den Namen der Mittelbezeichnung als ID. Sie können doppelte Namen für Mittel zulassen und zwei Bareinträge einschließen, z. B.:
Dann können Sie leicht folgendes bekommen:
Auf diese Weise wissen Sie, wenn Sie in Ihren Transaktionen auf MoneyTransferMean.UID = 2 verwiesen haben, dass dies eine Bargeldrückerstattung ist, anstatt zu wissen, dass es sich um einen Transaktionstyp handelt, der entweder eine Barrückerstattung oder eine Barzahlung sein kann.
quelle
Schließlich entschied ich mich, das Problem zu lösen, indem ich meine Entität
MoneyTransferMean
in zwei EntitätenPaymentMean
und duplizierteRefundMean
.Obwohl in der Implementierung ähnlich, macht die Unterscheidung zwischen den beiden Einheiten im Geschäft Sinn und war für mich die am wenigsten schlechte Lösung.
quelle