Monday, December 30, 2013

NHibernate: Foreign key must have same number of columns as the referenced primary key

If you get this kind of error when mapping many-to-one from child to parent, where the parent is using composite key which is mapped using mapping-by-code, e.g. ComponentAsId ..


System.TypeInitializationException was unhandled
  HResult=-2146233036
  Message=The type initializer for 'GoodCompositeMapping.SessionMapper.Mapper' threw an exception.
  Source=GoodCompositeMapping
  TypeName=GoodCompositeMapping.SessionMapper.Mapper
  StackTrace:
       at GoodCompositeMapping.SessionMapper.Mapper.get_SessionFactory()
       at GoodCompositeMapping.SampleLoad.LoadModel(Int32 id) in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\GoodCompositeMapping\SampleLoad.cs:line 21
       at TestComposite.Program.Main(String[] args) in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\TestComposite\Program.cs:line 15
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: NHibernate.FKUnmatchingColumnsException
       HResult=-2146232832
       Message=Foreign key (FK2F6A0A3BACD3E029:Model [CategoryId])) must have same number of columns as the referenced primary key (ProductCategory [ProductId, CategoryId])
       Source=NHibernate
       StackTrace:
            at NHibernate.Cfg.Configuration.LogAndThrow(Exception exception)
            at NHibernate.Cfg.Configuration.SecondPassCompileForeignKeys(Table table, ISet done)
            at NHibernate.Cfg.Configuration.SecondPassCompile()
            at NHibernate.Cfg.Configuration.BuildSessionFactory()
            at GoodCompositeMapping.SessionMapper.Mapper.GetSessionFactory() in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\GoodCompositeMapping\SessionMapper\Mapper.cs:line 58
            at GoodCompositeMapping.SessionMapper.Mapper..cctor() in c:\Users\Michael\Documents\GitHub\TestComposite\TestComposite\GoodCompositeMapping\SessionMapper\Mapper.cs:line 17
       InnerException:  


..chances are you are using a wrong mapping:

ManyToOne(x => x.ProductCategory, pm =>
    {
        pm.Column("ProductId");
        pm.Column("CategoryId");
    });

I saw a solution from stackoverflow that works:
ManyToOne(x => x.ProductCategory,
    c => c.Columns(
        new Action<NHibernate.Mapping.ByCode.IColumnMapper>[]
        {
            x  => x.Name("ProductId"),                        
            x  => x.Name("CategoryId")
        }));

This is the shorthand:
ManyToOne(x => x.ProductCategory, c => c.Columns(x => x.Name("ProductId"), x => x.Name("CategoryId")));


Happy Coding! ツ

No comments:

Post a Comment