2011-05-23 2 views
6

Ceci est très similaire à ma question précédente: FluentNHibernate: How to translate HasMany(x => x.Addresses).KeyColumn("PersonId") into automappingFluentNHibernate: AutoMapping OneToMany relation utilisant l'attribut et convention


Dire que j'ai ces modèles:

public class Person 
{ 
    public virtual int Id { get; private set; } 
    public virtual ICollection<Address> Addresses { get; private set; } 
} 

public class Address 
{ 
    public virtual int Id { get; private set; } 
    public virtual Person Owner { get; set; } 
} 

Je veux FluentNHibernate créer les tableaux ci-dessous :

Person 
    PersonId 
Address 
    AddressId 
    OwnerId 

Ceci peut être facilement réalisé en utilisant fluen t mapping:

public class PersonMapping : ClassMap<Person> 
{ 
    public PersonMapping() 
    { 
     Id(x => x.Id).Column("PersonId"); 
     HasMany(x => x.Addresses).KeyColumn("OwnerId"); 
    } 
} 

public class AddressMapping : ClassMap<Address> 
{ 
    public AddressMapping() 
    { 
     Id(x => x.Id).Column("AddressId"); 
     References(x => x.Person).Column("OwnerId"); 
    } 
} 

Je veux obtenir le même résultat en utilisant le mappage automatique. J'ai essayé les conventions suivantes:

class PrimaryKeyNameConvention : IIdConvention 
{ 
    public void Apply(IIdentityInstance instance) 
    { 
     instance.Column(instance.EntityType.Name + "Id"); 
    } 
} 

class ReferenceNameConvention : IReferenceConvention 
{ 
    public void Apply(IManyToOneInstance instance) 
    { 
     instance.Column(string.Format("{0}Id", instance.Name)); 
    } 
} 

// Copied from @Fourth: https://stackoverflow.com/questions/6091290/fluentnhibernate-how-to-translate-hasmanyx-x-addresses-keycolumnpersonid/6091307#6091307 
public class SimpleForeignKeyConvention : ForeignKeyConvention 
{ 
    protected override string GetKeyName(Member property, Type type) 
    { 
     if(property == null) 
      return type.Name + "Id"; 
     return property.Name + "Id"; 
    } 
} 

Mais il a créé les tableaux suivants:

Person 
    PersonId 
Address 
    AddressId 
    OwnerId 
    PersonId // this column should not exist 

J'ajouté un AutoMappingOverride:

public class PersonMappingOverride : IAutoMappingOverride<Person> 
{ 
    public void Override(AutoMapping<Person> mapping) 
    { 
     mapping.HasMany(x => x.Addresses).KeyColumn("OwnerId"); 
    } 
} 

Ce ont correctement résolu le problème. Mais je veux obtenir le même résultat en utilisant l'attribut & convention. J'ai essayé:

public class Person 
{ 
    public virtual int Id { get; private set; } 

    [KeyColumn("OwnerId")] 
    public virtual ICollection<Address> Addresses { get; private set; } 
} 

class KeyColumnAttribute : Attribute 
{ 
    public readonly string Name; 

    public KeyColumnAttribute(string name) 
    { 
     Name = name; 
    } 
} 

class KeyColumnConvention: IHasManyConvention 
{ 
    public void Apply(IOneToManyCollectionInstance instance) 
    { 
     var keyColumnAttribute = (KeyColumnAttribute)Attribute.GetCustomAttribute(instance.Member, typeof(KeyColumnAttribute)); 
     if (keyColumnAttribute != null) 
     { 
      instance.Key.Column(keyColumnAttribute.Name); 
     } 
    } 
} 

Mais il a créé ces tableaux:

Person 
    PersonId 
Address 
    AddressId 
    OwnerId 
    PersonId // this column should not exist 

Voici le reste de mon code:

ISessionFactory sessionFactory = Fluently.Configure() 
    .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString)) 
    .Mappings(m => 
       m.AutoMappings.Add(AutoMap.Assemblies(typeof(Person).Assembly) 
        .Conventions.Add(typeof(PrimaryKeyNameConvention)) 
          .Conventions.Add(typeof(PrimaryKeyNameConvention)) 
          .Conventions.Add(typeof(ReferenceNameConvention)) 
          .Conventions.Add(typeof(SimpleForeignKeyConvention)) 
          .Conventions.Add(typeof(KeyColumnConvention))) 

       //m.FluentMappings 
       // .Add(typeof (PersonMapping)) 
       // .Add(typeof (AddressMapping)) 
    ) 
    .ExposeConfiguration(BuildSchema) 
    .BuildConfiguration() 
    .BuildSessionFactory(); 

Toutes les idées? Merci.


Mise à jour:

Le projet de test peut être téléchargé à partir here.

Répondre

6

Sigh ... Apprendre NHibernate est vraiment une expérience de tirage de cheveux.

Quoi qu'il en soit, je pense que j'ai finalement compris comment résoudre ce problème: Il suffit de supprimer le SimpleForeignKeyConvention et tout ira bien.

Il semble que le SimpleForeignKeyConvention soit en conflit avec les deux ReferenceKeyConvention & KeyColumnConvention. Il a une priorité plus élevée que KeyColumnConvention mais une priorité inférieure à ReferenceKeyConvention.

public class SimpleForeignKeyConvention : ForeignKeyConvention 
{ 
    protected override string GetKeyName(Member property, Type type) 
    { 
     if(property == null) 
      // This line will disable `KeyColumnConvention` 
      return type.Name + "Id"; 

     // This line has no effect when `ReferenceKeyConvention` is enabled. 
     return property.Name + "Id"; 
    } 
} 
+0

soin d'accepter la réponse, donc d'autres connaissent sa solution à votre problème – Firo

+0

@Firo: J'ai reçu un message _ "Vous pouvez accepter votre propre réponse en x heures" _ (pour le moment, x = 16). Je vais essayer à nouveau demain. –

1

J'ai testé vos classes avec la fonction de mappage automatique de FHN et elle ne crée pas cette deuxième table PersonId on Address. J'utilise FHN v1.2.0.721 de here

+0

Merci pour les tests! Avez-vous inclus 'PersonMappingOverride' dans la configuration? Si oui, oui, il ne crée pas cette deuxième table 'PersonId' sur' Address'.Mais il est supposé être exclu de la configuration, car je veux obtenir le même résultat en utilisant 'KeyColumnAttribute' &' KeyColumnConvention'. J'ai mis à jour ma question avec un lien de téléchargement de mon projet de test, qui devrait reproduire le problème. –

+1

Maintenant, vous avez changé les noms des propriétés, non? (pour prouver que ...) Alors lisez ce fil similaire (Pour éviter d'avoir deux colonnes de clé étrangère différentes ...): http://stackoverflow.com/questions/310641/fluent-nhibernate-comment-create-one -to-many-bidirectional-mapping – VahidN

Questions connexes