Search code examples
nhibernatefluent-nhibernatenhibernate-mappingfluent-nhibernate-mapping

Fluent NHibernate generates extra columns


We are using Fluent NHibernate for data object model in the company i work. A couple of days ago, we encountered an issue that Fluent NHibernate generates an extra column which does exist neither in model nor in mapping. Here is the situation:

My Model: FirstClass.cs

public class FirstClass
{
    public virtual int Id { get; private set; }
    public virtual SecondClass MyReference { get; set; }
    public virtual DateTime DecisionDate { get; set; }
}

My Mapping:

public class FirstClassMap : ClassMap<FirstClass>
{
    public FirstClassMap()
    {
        Id(x => x.Id);
        Map(x => x.DecisionDate);

        References(x => x.MyReference);
    }
}

After building the schema with the following code,

Instance._sessionFactory = Fluently.Configure()
                .Database(MySQLConfiguration.Standard
                    .ConnectionString(connectionString)
                    .ShowSql())
                .ExposeConfiguration(c =>
                {
                    c.Properties.Add("current_session_context_class", ConfigurationHelper.getSetting("SessionContext"));
                })
                .ExposeConfiguration(BuildSchema)
                .Mappings( m => m.FluentMappings.AddFromAssemblyOf<Community>())
                .BuildSessionFactory();

An extra column named "SecondClass_id" is produced with index and foreign key to SecondClass table with Id column. Here is the table produced:

CREATE TABLE `FirstClass` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `DecisionDate` datetime DEFAULT NULL,
  `MyReference_id` int(11) DEFAULT NULL,
  `SecondClass_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Id`),
  KEY `MyReference_id` (`MyReference_id`),
  KEY `SecondClass_id` (`SecondClass_id`),
  CONSTRAINT `FK4AFFB59B2540756F` FOREIGN KEY (`MyReference_id`) REFERENCES `SecondClass` (`Id`),
  CONSTRAINT `FK4AFFB59B51EFB484` FOREIGN KEY (`SecondClass_id`) REFERENCES `SecondClass` (`Id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

I found that, if I rename "MyReference" to "SecondClass" (same name as the class type), there is no extra column created. But i want to use my property with the name i specified, not with the class name. Why that extra column is created? How do i fix that? I don't want extra foreign key columns hanging around.


Solution

  • This often happens when you're using FNH and you have a two-way relationship between entities.

    public class FirstClass
    {
        public virtual SecondClass MyReference { get; set; }
    }
    
    public class SecondClass
    {
        public virtual List<FirstClass> ListOfFirstClass { get; set; }
    }
    
    public class FirstClassMap : ClassMap<FirstClass>
    {
        public FirstClassMap()
        {
            References(x => x.MyReference);
        }
    }
    
    public class SecondClassMap : ClassMap<SecondClass>
    {
        public SecondClassMap()
        {
            HasMany(x => x.ListOfFirstClass);
        }
    }
    

    To fix this you have to override the column name used in either ClassMap, like so:

    public class SecondClassMap : ClassMap<SecondClass>
    {
        public SecondClasssMap()
        {
            HasMany(x => x.ListOfFirstClass).KeyColumn("MyReference_id");
        }
    }
    

    or:

    public class FirstClassMap : ClassMap<FirstClass>
    {
        public FirstClassMap()
        {
            References(x => x.MyReference).Column("SecondClass_id");
        }
    }
    

    The reason for this is that FNH treats each mapping as a separate relationship, hence different columns, keys, and indexes get created.