Question

J'ai essentiellement un type de valeur Money, qui se compose de Amount et Currency. Je dois associer plusieurs valeurs Money dans une table, qui a plusieurs champs pour le montant, mais une seule monnaie. Dans les mots d'ordre, j'ai la table:

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

Ce qui doit être mis en correspondance avec une classe avec 2 valeurs monétaires (qui peuvent logiquement jamais des devises différentes):

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

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

(exemple est un peu simplifiée)

Le schéma de la table ne peut pas être changé. Je suis heureux de mettre en œuvre un IUserType, si nécessaire, mais je ne peux pas comprendre comment accéder à la colonne Currency pour les deux valeurs.

Comment puis-je la carte en utilisant ce NHibernate?

Était-ce utile?

La solution

Il est impossible.

Si vous créez un argent UserType le but du type est de combiner deux primitives dans un nouveau type de données unique. Ce type de données est maintenant une seule unité atomique. Parce que le UserType est considéré comme un type atomique les deux colonnes doivent être présents pour chaque valeur de l'argent cartographié. La règle NHibernate est l'application est en fait sémantiquement correcte. Vous avez deux valeurs d'argent. Par conséquent, vous devez avoir deux monnaies -. Ils ne peuvent pas partager un parce qu'un seul type d'argent a une devise et le montant et qui est une unité de données atomique maintenant, il ne peut pas être divisé ou partagé

Vous voulez parfois traiter la monnaie comme variable et a donc besoin de sa propre colonne, et à d'autres moments fixes afin que plusieurs UserTypes peuvent tous partager une colonne. Même si cela était valable, qu'elle ne repose pas sur la façon dont un argent est défini, comment NHibernate savoir ce que vous vouliez faire quand? Le système ne peut pas savoir exactement ce que vous voulez à un moment donné. Vous devez maintenant également enregistrer des données supplémentaires avec le type d'argent que spécifié comment était destiné à être utilisé une valeur donnée.

En bout de ligne, vos colonnes comme on le ne peut pas être mis en correspondance en tant que UserType. Si vous ne pouvez pas modifier le schéma, la seule façon que vous pouvez faire est de retrouver tous les trois colonnes comme primitives normales, puis construire (et déconstruire) un type d'argent dans votre code d'application.

Et pour quelles fins? Je suis vraiment surpris que quelqu'un même comme Fowler suggère cette approche comme une sorte de « meilleures pratiques » sans tenir compte de vraiment les détails réels. Le fait est la plupart des données est un ensemble où la monnaie est dictée pour une ligne par un facteur souvent implicite ou externe comme pays d'origine ou pays où une entreprise exerce ses activités, etc., etc.

Les occasions où vous pourriez en fait même besoin devise que vous avez souvent tant d'autres bagages qui découle de plusieurs monnaies telles que les taux de change courants, etc qui ayant la monnaie comme faisant partie intégrante d'un type d'argent est même pas utile. Il est pratique, mais pour des données qui est très peu pratique à travailler et ne peuvent pas être faites autrement. La plupart de la monnaie de temps est fixe et généralement peut même être inférée. Ainsi, un type d'argent dans les cas typiques ne peuvent pas non plus se rapprocher de ce que vous avez vraiment besoin - une conversion, ou il est tout simplement des informations inutiles. À quelques exceptions près le type d'argent devient juste un dingleberry sur le cul de l'application.

Avant de passer beaucoup de temps à essayer de mettre en œuvre quelque chose pour peut-être peu ou aucune autre raison que d'une certaine manière les gens ont commencé à appeler cette « meilleure pratique », demandez-vous êtes-vous jamais même allez avoir besoin de l'utiliser pour quoi que ce soit?

Autres conseils

Il est impossible parce qu'il n'a pas de sens quand on considère lecture et l'écriture des entités .

Considérons le cas où Valeur1 est USD 20 et Value2 est GBP 40. Comment voulez-vous persister il?

Qu'en est-il changer vos classes comme ça?

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; }
}

Maintenant, vous pouvez écrire un type d'utilisateur pour MoneyCollection.

Note: Vous devez vous assurer que le MoneyCollection a un nombre constant, ou au moins un nombre maximal de valeurs, parce que vous devez mapper à un nombre constant de colonnes. Vérifiez cela dans la classe elle-même.

Je suis un débutant d'apprendre seulement et travailler avec NHibernate pendant quelques mois, mais est-il pas possible de faire un complexe usertype (IEnhancedUserType) qui écrit à plusieurs colonnes, alors qu'une colonne redondante?

Difficile à expliquer, mais si vous associez une propriété dans votre entité à la colonne de monnaie qui prend en charge les actions de lecture / écriture et vous référer à la même colonne plusieurs fois dans la cartographie complexe usertype et désactiver insert et mise à jour, ainsi ce qui en fait une colonne en lecture seule, ne serait pas que le travail? J'ai pensé à essayer de faire un usertype comme celui-ci pour voir si elle fonctionne (depuis que je ne l'ai pas encore essayé, je n'ai pas de code exemple atm)

Je sais qu'il est un retard de quelques années -. Mais j'ai une solution

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;
    }
}

Cartographie:

Map(Reveal.Member<Basket>("_subTotal")).Column("SubTotal");
Map(Reveal.Member<Basket>("_shipping")).Column("Shipping");
Map(Reveal.Member<Basket>("_currency")).Column("Currency");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top