How to reference parent object in the same table with nhibernate fluent auto mappings?

I am trying to use FluentNHibernate AutoMappings to create an object with a reference to its parent. I was able to do it using ClassMap <>, but now I want to move everything to AutoMappings. I have a table with the following schema:

CREATE TABLE [dbo].[Job]
(
   [Id] INT NOT NULL IDENTITY(1,1), 
   [ParentId] INT NULL, 
   PRIMARY KEY ([Id]), 
   CONSTRAINT [FK_Job_Parent] FOREIGN KEY ([ParentId]) REFERENCES [Job]([Id]) 
)

      

And the following C # code:

using FluentNHibernate;
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;
using System;
using System.Configuration;

namespace NHibernateTest
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var sessionFactory = Fluently.Configure()
              .Database(MsSqlConfiguration.MsSql2008.ConnectionString(ConfigurationManager.ConnectionStrings["Default"].ConnectionString))
              .Mappings(m =>
              {
                  m.AutoMappings.Add(
                      AutoMap.AssemblyOf<Program>(new MappingConfig()).Conventions.Setup(conv =>
                  {
                      conv.Add<DefaultReferenceConvention>();
                      conv.Add<DefaultHasManyConvention>();
                      conv.Add<SimpleForeignKeyConvention>();
                  }));
              })
              .BuildSessionFactory();

            using (var session = sessionFactory.OpenSession())
            {
                using (var tran = session.BeginTransaction())
                {
                   var jobs = session
                        .QueryOver<Job>()
                        .List<Job>();

                    tran.Commit();
                }
            }
        }
    }

    public class Job
    {
        public virtual int Id { get; set; }

        public virtual Job Parent { get; set; }
    }

    public class MappingConfig : DefaultAutomappingConfiguration
    {
        public override bool ShouldMap(Type type)
        {
            return type == typeof(Job);
        }
    }

    public class SimpleForeignKeyConvention : ForeignKeyConvention
    {
        protected override string GetKeyName(Member property, Type type)
        {
            if (property == null)
            {
                return type.Name + "Id";
            }

           return property.Name + "Id";
        }
    }

    public class DefaultHasManyConvention : IHasManyConvention
    {
        public void Apply(IOneToManyCollectionInstance instance)
        {
            instance.Key.Column(string.Format("{0}{1}", instance.EntityType.Name, "Id"));
            instance.LazyLoad();
        }
    }

    public class DefaultReferenceConvention : IReferenceConvention
    {
        public void Apply(IManyToOneInstance instance)
        {
            var col = string.Format("{0}Id", instance.Class.Name);
            instance.Column(col);
            instance.LazyLoad();
        }
    }
}

      

I get:

An invalid or incomplete configuration was used when creating the SessionFactory. See the PotentialReasons and InnerException collection for more details.

The foreign key (FK7D5D63A6AE42E0BA: Job [JobId, ParentId])) must have the same number of columns as the referenced primary key (Job [Id])

Is there a way to do this using only auto mappings?

+3


source to share


1 answer


Yours DefaultReferenceConvention

seems to be in conflict with yours SimpleForeignKeyConvention

. One uses the property name as the basis for the column name, and the other uses the property type. It looks like for some reason Fluent NH uses both of them and thinks you have a composite key.

Uninstall DefaultReferenceConvention

and check if it fixes it. This is redundant anyway, because the default column name assignment for Fluent NH is already by default {Class.Name}Id

.



The loose NH conventions are great for painting your displays with wide brush strokes, but they are not a suitable tool for changing the column name for a single object. In this case, you should define instead IAutoMappingOverride<T>

.

0


source







All Articles