2009-09-01 4 views
5

J'essaie de comprendre comment mapper une propriété IDictionary dans RTM 1.0 fluide. Selon ma compréhension, cela se traduit par une association ternaire.Code courant pour mapper un IDictionary <SomeEntity, int>?

Exemple:

class Bar 
{ 
    public IDictionary<SomeEntity, int> Foo {get; set;} 
} 

Bar.hbm.xml contient alors:

<map name="Foo" table="BarFooTable"> 
    <key column="..."/> 
    <index-many-to-many class="SomeEntity" column="SomeEntity_Id"/> 
    <element column="Value" type="int"/> 
</map> 

Qu'est-ce que je dois écrire dans NHibernate couramment pour produire ce xml mapping?

Le point d'intérêt ici est que la clé est un type d'entité alors que la valeur est un type de valeur. (edit: Au moins, cela semble se distinguer des autres exemples et questions qui circulent sur les groupes stackoverflow ou google, qui sont value-value ou key-key)

Après beaucoup d'expérimentation je peux produire une cartographie pour un IDictionary<SomeEntity,SomeEntity> (types d'entité pure):

HasManyToMany(x => x.Foo) 
     .AsMap("Key") 
     .AsTernaryAssociation("Key2", "Value") 
     ; 

Je peux aussi produire une cartographie pour un IDictionary<int,int> (types de valeur pure):

HasMany(x => x.Foo) 
    .AsMap<int>("Key") 
    .Element("Value") 
    ; 

je peux même obtenir un moyen de produire une cartographie pour un IDictionary<int, SomeValue), bien que rien que NHibernate acceptera.

Mais je ne peux pas comprendre comment produire un mappage pour un IDictionary<SomeValue, int> qui est ce que je veux. Quelqu'un peut-il donner quelques conseils?

+0

crossposted à http://groups.google.com/group/fluent-nhibernate/browse_thread/thread/b1b335ff5f9a6a40 – fostandy

Répondre

1

je suis tombé sur le même problème, et n » était pas t heureux de mélanger fluides et mappages hbm. Vous pouvez voir ma correction here.

0

Il semble que nous avons le même problème:

How to map this in Fluent.NHibernate

Je viens d'utiliser hbm.xml (qui a été généré par Fluent.Nhibernate dans mon projet) Je l'ai modifié un peu oufcourse. Si vous définissez

.Mappings(m => 
    {            
     m.FluentMappings.AddFromAssemblyOf<DomainClass>() 
         .ExportTo("Path"); 
     m.HbmMappings.AddFromAssemblyOf<DomainClass>(); 
    }) 

et si vous avez à la fois ClassMap et hbm.xml le hbm.xml devrait remplacer le ClassMap, vous serez bien jusqu'à ce qu'il est fixé.

j'ai aussi besoin id naturel pour ma classe et il est pas pris en charge aussi avec Fluent.Nhibernate, donc je n'avais pas d'autre choix que d'utiliser hbm.xml

+0

Oui, c'est actuellement la façon dont je suis faire des choses aussi bien. Malheureusement, j'ai une classe assez lourde qui, même si elle a beaucoup de propriétés qui peuvent être mappées avec fluence, a aussi un IDictionary . Ma «solution» consistait à séparer la fonctionnalité en classes séparées (l'une mappée couramment, l'autre via hbm.xml brut) et à utiliser un mappage un-à-un, mais pour des raisons de performances, il est maintenant souhaitable d'éliminer la jointure/extra select qui se produit à partir de cela. (Voir http://groups.google.com/group/fluent-nhibernate/browse_frm/thread/b5fe376e257436e9/35d9cf5cef4303d0) – fostandy

2
HasMany(x => x.Foo) 
    .KeyColumn("BarId") 
    .Element("IntValue") 
    .AsMap<SomeEntity>("SomeEntityId") 
    .AsTernaryAssociation("SomeEntityId"); 
+0

Juste eu le même problème, basé sur votre solution j'ai fini par 'HasManyToMany (x => x. collection) \t \t \t \t .ParentKeyColumn ("ParentId") \t \t \t \t .ChildKeyColumn ("childID") \t \t \t \t .AsMap ("childID"). élément ("Valeur", p => p .Colonne ("Valeur"). Type ()) \t \t \t \t .AsTernaryAssociation ("ChildID", "Value") \t \t \t \t \t \t \t \t .Table ("Relationstable"); ' –

0

Compte tenu de ces (simplifié) classes:

class LetterTemplate 
{ 
    IDictionary<State, FieldAccessOptionality> StateAccess {get; protected set;} 
} 

class State 
{ 
} 

enum FieldAccessOptionality 
{ 
} 

Cela a fonctionné pour moi.

(Oui, je sais que la valeur est une Enum, mais le principe est le même que celui d'un int).

HasManyToMany(x => x.StateAccess) 
    .ParentKeyColumn("`letter_template`") 
    .ChildKeyColumn("`state`") 
    .AsMap<State>("`state`") 
    .Element("`access`", 
     p => 
     p.Type<IntEnumType<FieldAccessOptionality>>()) 
    .AsTernaryAssociation("`state`", "`access`") 
    .Table("`letter_template_state_access`"); 

Notez le IntEnumType <> classe qui convertit d'un ENUM à un int pour NHibernate. Si vous mappez un int au lieu d'une énumération, vous pouvez simplement utiliser le standard NHibernate Int32Type IUserType. La liste complète de cette classe est la suivante:

public class IntEnumType<T> : IUserType where T : struct 
{ 
    public object Assemble(object cached, object owner) 
    { 
    return cached; 
    } 

    public object DeepCopy(object value) 
    { 
    return value; 
    } 

    public object Disassemble(object value) 
    { 
    return value; 
    } 

    public new bool Equals(object a, object b) 
    { 
    return Object.Equals(a, b); 
    } 

    public int GetHashCode(object x) 
    { 
    if (x == null) 
     return 0; 
    else 
     return x.GetHashCode(); 
    } 

    public bool IsMutable 
    { 
    get { return false; } 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
    object result = NHibernateUtil.Int32.NullSafeGet(rs, names); 
    if (result == null) 
    { 
     return null; 
    } 
    else 
    { 
     Type typ = Enum.GetUnderlyingType(typeof(T)); 
     result = Convert.ChangeType(result, typ); 
     return Enum.ToObject(typeof(T), result); 
    } 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
    if (value == null) 
     ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; 
    else 
     ((IDataParameter)cmd.Parameters[index]).Value = Convert.ChangeType(value, typeof(int)); 
    } 

    public object Replace(object original, object target, object owner) 
    { 
    return original; 
    } 

    public Type ReturnedType 
    { 
    get { return typeof(T); } 
    } 

    public SqlType[] SqlTypes 
    { 
    get 
    { 
     SqlType type = new SqlType(DbType.Int32); 
     return new SqlType[] { type }; 
    } 
    } 

} 
Questions connexes