Un po 'di conoscenza del dominio
Sto scrivendo un software POS (Point Of Sales) che consente di pagare merci o rimborsarle. Quando si paga o si rimborsa, è necessario specificare quale trasferimento di denaro si intende utilizzare: contanti, EFT (~ = carta di credito), carta fedeltà, voucher, ecc.
Questi mezzi di trasferimento di denaro sono un insieme finito e noto di valori (una sorta di enum).
La parte difficile è che devo essere in grado di memorizzare un sottoinsieme personalizzato di questi mezzi sia per i pagamenti che per i rimborsi (i due set potrebbero essere diversi) sul terminale POS.
Per esempio:
- Mezzi di pagamento disponibili: contanti, EFT, carta fedeltà, voucher
- Il rimborso disponibile significa: contanti, buono
Stato attuale di attuazione
Ho scelto di implementare il concetto di trasferimento di denaro come segue:
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...
}
Il motivo per cui non è un "semplice enum" è che esiste un comportamento all'interno di queste classi. Ho anche dovuto dichiarare le classi interne pubbliche (anziché private) per poterle fare riferimento nella mappatura FluentNHibernate (vedi sotto).
Come viene usato
Sia il mezzo di pagamento che quello di rimborso sono sempre memorizzati o recuperati nel / dal DB come set. Sono in realtà due insiemi distinti anche se alcuni valori all'interno di entrambi gli insiemi possono essere gli stessi.
Caso d'uso 1: definire una nuova serie di mezzi di pagamento / rimborso
- Elimina tutti i mezzi di pagamento / rimborso esistenti
- Inserisci quelli nuovi
Caso d'uso 2: recuperare tutti i mezzi di pagamento / rimborso
- Ottieni una raccolta di tutti i mezzi di pagamento / rimborso memorizzati
Problema
Sono bloccato con il mio progetto attuale sull'aspetto della persistenza. Sto usando NHibernate (con FluentNHibernate per dichiarare le mappe di classe) e non riesco a trovare un modo per mapparlo su uno schema DB valido.
Ho scoperto che è possibile mappare una classe più volte usando nome-entità tuttavia non sono sicuro che sia possibile con le sottoclassi.
Quello che non sono pronto a fare è modificare l'API pubblica MoneyTransferMean per poterla perseguire (ad esempio aggiungendo un bool isRefund
per differenziare tra i due). Tuttavia, aggiungere un campo discriminatore privato o giù di lì è ok.
La mia mappatura attuale:
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...
Questa mappatura viene compilata tuttavia produce solo 1 tabella e non sono in grado di distinguere tra pagamento / rimborso durante l'interrogazione di questa tabella.
Ho provato a dichiarare due mappature che fanno riferimento sia MoneyTransferMean
a tabella che a nome-entità diversi, ma ciò mi porta a un'eccezione Duplicate class/entity mapping MoneyTransferMean+CashMoneyTransferMean
.
Ho anche provato a duplicare i mapping delle sottoclassi ma non riesco a specificare un "mapping principale" che mi porta alla stessa eccezione di cui sopra.
Domanda
Esiste una soluzione per mantenere le mie attuali entità di dominio?
In caso contrario, quale sarebbe il più piccolo refattore che devo eseguire sulle mie entità per renderle persistenti con NHibnernate?
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).
: Perchè no? È un cambiamento semplice e dolce che dovrebbe risolvere il tuo problema. È possibile effettuare fino a tre valori possibili (anche se due saranno anche fare con i record duplicati oFlag
tipo):Payment
,Refund
,Both
. Se due valori fanno per te, labool
proprietà è fantastica.