FluentNHibernate: Automatically Use OneToMany Relationship Using Attribute and Agreement

This is very similar to my previous question: FluentNHibernate: how to translate HasMany (x => x.Addresses) .KeyColumn ("PersonId") into automation


Let's say I have these models:

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

I want FluentNHibernate to create the following tables:

 Person PersonId Address AddressId OwnerId 

This can be easily achieved using free 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"); } } 

I want to get the same result using automatic matching. I tried the following conventions:

 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: /questions/888793/fluentnhibernate-how-to-translate-hasmanyx-xaddresseskeycolumnpersonid-into-automapping6091307#6091307 public class SimpleForeignKeyConvention : ForeignKeyConvention { protected override string GetKeyName(Member property, Type type) { if(property == null) return type.Name + "Id"; return property.Name + "Id"; } } 

But he created the following tables:

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

So, I added AutoMappingOverride:

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

This solved the problem correctly. But I want to get the same result using attribute and convention. I tried:

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

But he created these tables:

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

Below is the rest of my 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(); 

Any ideas? Thanks.


Update:

Test project can be downloaded from here .

+6
source share
2 answers

Sigh ... Studying NHibernate is really a hairstyle.

In any case, I finally figured out how to solve this problem: just remove SimpleForeignKeyConvention and everything will work fine.

SimpleForeignKeyConvention conflict with ReferenceKeyConvention and KeyColumnConvention . It has a higher priority than KeyColumnConvention , but a lower priority than 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"; } } 
+6
source

I checked your classes with the FHN auto-matching function and did not create this second PersonId on Address table. I am using FHN v1.2.0.721 from here

+1
source

Source: https://habr.com/ru/post/888783/


All Articles