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)); } }
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)))
Any ideas? Thanks.
Update:
Test project can be downloaded from here .