Domanda

Io fondamentalmente ha un tipo di valore Money, che consiste di Amount e Currency. Ho bisogno di mappare più valori Money in una tabella, che ha più campi per quantità, ma una sola moneta. In altri termini, ho la tabella:

Currency     Amount1    Amount2
===============================
USD          20.00      45.00

Il che deve essere mappato a una classe con 2 valori monetari (che può logicamente mai avere valute differenti):

class Record
{ 
    public Money Value1 { get; set; }
    public Money Value2 { get; set; }
}

struct Money 
{
    public decimal Amount { get; set; }
    public string Currency { get;set; }
} 

(Esempio è un po 'semplificata)

Lo schema della tabella non può essere modificata. Sono felice di implementare un IUserType, se necessario, ma non riesco a capire come accedere colonna Currency per entrambi i valori.

Come faccio Visualizza la mappa usando NHibernate?

È stato utile?

Soluzione

Non è possibile.

Se si crea un UserType denaro lo scopo del tipo è quella di combinare due primitive in un nuovo tipo di dato singolo. Tale tipo di dati è ora una singola unità atomica. Poiché l'UserType è considerato un tipo atomico entrambe le colonne devono essere presenti per ogni valore mappato denaro. La regola è far rispettare NHibernate è infatti semanticamente corretto. Hai due valori monetari. Pertanto è necessario disporre di due valute -. Non possono condividere uno perché un singolo tipo di denaro ha una valuta e l'importo e che è un'unità di dati atomica ora, non può essere diviso o condiviso

Si vuole, a volte il trattamento di valuta come variabile, e quindi necessitano di una propria colonna, e altre volte come fisso in modo che più UserTypes possono condividere una colonna. Anche se fosse valida, che non si basa su come un denaro viene definito, come sarebbe NHibernate sapere ciò che si voleva fare quando? Il sistema non può solo sapere cosa si vuole in un dato momento. Si sarebbe ora necessario anche salvare i dati aggiuntivi con il tipo di denaro che ha specificato come un dato valore è stato destinato ad essere utilizzato.

La linea inferiore, le colonne come lo è non può essere mappata come UserType. Se non è possibile modificare lo schema, l'unico modo è possibile farlo è quello di mappare tutte le tre colonne come primitivi normali e quindi di costruire (e deconstruct) un tipo di denaro nel codice dell'applicazione.

E per ciò che finisce? Sono davvero sorpreso che qualcuno piace nemmeno Fowler suggerisce che questo approccio come una sorta di "best practice", senza realmente considerare i dati reali. Il fatto è che la maggior parte dei dati è un insieme in cui la valuta è dettato per una riga da qualche fattore spesso implicita o esterno come paese di origine o del paese in cui un'azienda opera ecc ecc

Le occasioni in cui si potrebbe effettivamente nemmeno bisogno di valuta avete spesso tanto altro bagaglio che nasce dalla più valute come i tassi di cambio correnti, ecc che avere la valuta come parte integrante di un tipo Il denaro non è nemmeno che utile. Si tratta di una comodità, ma per i dati che è molto scomodo per lavorare con e non possono essere fatte in altro modo. La maggior parte della moneta tempo è fisso e di solito può anche essere dedotto. Quindi un tipo di denaro nei casi tipici o non può venire vicino a quello che si ha realmente bisogno - una conversione, o si tratta semplicemente di informazioni inutili. Con poche eccezioni il tipo di denaro diventa solo un dingleberry sul culo della domanda.

Prima di spendere un sacco di tempo a cercare di implementare qualcosa di forse poco o nessun altro motivo che in qualche modo le persone hanno iniziato a chiamare questa "best practice", chiedetevi stai mai nemmeno intenzione di bisogno di usarlo per qualsiasi cosa?

Altri suggerimenti

Non è possibile, perché non ha senso se si considera lettura e la scrittura entità.

Si consideri il caso in cui è Valore1 USD 20 e value2 è GBP 40. Come vi persistono?

Che dire di cambiare le vostre classi come questo?

class Record
{ 
    public MoneyCollection Money { get; set; }
}

class MoneyCollection
{
    public MoneyCollection(string currency, params decimal[] amount1) { /*...*/ }
    public decimal[] Amount { get; private set; }
    public string Currency { get; private set; }
    public Money[] Money
    {
      get
      {
        return Amount.Select(x => new Money(Currency, x)).ToArray();
      }
    }
} 

class Money 
{
    public Money(decimal amount, string currency ) { /* ... */ }
    public decimal Amount { get; private set; }
    public string Currency { get; private set; }
}

Ora si può scrivere un tipo di utente per MoneyCollection.

Nota: è necessario assicurarsi che il MoneyCollection ha un numero costante, o almeno un numero massimo di valori, perché è necessario farlo corrispondere ad un numero costante di colonne. Controllare questo nella classe stessa.

Sono solo un principiante solo imparare a conoscere e lavorare con NHibernate per un paio di mesi, ma non è possibile fare un tipo utente complessa (IEnhancedUserType), che scrive a più colonne, mentre una colonna sarà ridondante?

difficile da spiegare, ma se si mappa una proprietà nel vostro soggetto alla colonna di moneta che si occupa di azioni di lettura / scrittura e si riferiscono alla stessa colonna più volte all'interno della mappatura usertype complesso e spegnere di inserimento e aggiornamento, quindi che lo rende una colonna di sola lettura, non sarebbe che il lavoro? Ho pensato di provare a fare un tipo utente come questo per vedere se funziona (visto che non ho ancora provato, non ho alcun codice di esempio atm)

So che è un paio di anni di ritardo -. Ma ho una soluzione

private decimal _subTotal;
private decimal _shipping;
private CurrencyIsoCode _currency;

public virtual Money SubTotal
{
    get { return new Money(_subTotal, _currency); }
    set
    {
        _subTotal = value.Amount;
        _currency = value.CurrencyCode;
    }
}

public virtual Money Shipping
{
    get { return new Money(_shipping, _currency); }
    set
    {
        _shipping = value.Amount;
        _currency = value.CurrencyCode;
    }
}

Mapping:

Map(Reveal.Member<Basket>("_subTotal")).Column("SubTotal");
Map(Reveal.Member<Basket>("_shipping")).Column("Shipping");
Map(Reveal.Member<Basket>("_currency")).Column("Currency");
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top