Search code examples
nhibernateormnhibernate-mapping

Parent and child mapping in Nhibernate


I have two tables in a database: Order and OrderLine. OrderLine has a not nullable column (OrderId) with foreign key pointing to Order.Id.

In code I have two classes: Order and OrderLine. Order has a collection of OrderLines but OrderLine does not have a reference to Order.

It is it correct that you can’t map this relation without introducing a reference from OrderLine to Order or maintain a private field with the order id inside the OrderLine as indicated in this blog post (variation 3)?

Thanks in advance…

enter image description here

The following code shows the enties and mappings

namespace NhibernateMappingTests
{
    [TestClass]
    public class MappingExample2
    {
        [TestMethod]
        public void InsertTest()
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    Order order = new Order();
                    order.AddOrderLine(new OrderLine());
                    session.Save(order);
                    transaction.Commit();
                }
            }
        }
    }

    public class Order
    {
        public Order()
        {
            OrderLines = new List<OrderLine>();
        }

        public int Id { get; set; }
        public IList<OrderLine> OrderLines { get; set; }

        public void AddOrderLine(OrderLine orderLine)
        {
            OrderLines.Add(orderLine);
        }
    }

    public class OrderLine
    {
        public int Id { get; set; }
    }

    public class OrderMap : ClassMap<Order>
    {
        public OrderMap()
        {
            Not.LazyLoad();
            Id(x => x.Id).GeneratedBy.Identity();
            HasMany(x => x.OrderLines)
                .AsBag()
                .Cascade.All()
                .KeyColumn("OrderId");
        }
    }

    public class OrderLineMap : ClassMap<OrderLine>
    {
        public OrderLineMap()
        {
            Not.LazyLoad();
            Id(x => x.Id).GeneratedBy.Identity();
        }
    }

    public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;

        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                    InitializeSessionFactory();

                return _sessionFactory;
            }
        }

        private static void InitializeSessionFactory()
        {
            _sessionFactory = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008.ConnectionString(@"data source=(local)\db01;initial catalog=MyDatabase;persist security info=false;packet size=4096;integrated security=sspi;").ShowSql())
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<TimeSeries>())
                //.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true))
                .BuildSessionFactory();
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}

It result in the following exception:

Test method NhibernateMappingTests.MappingExample2.InsertTest threw exception: NHibernate.Exceptions.GenericADOException: could not insert: [NhibernateMappingTests.OrderLine][SQL: INSERT INTO [OrderLine] DEFAULT VALUES; select SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'OrderId', table 'MyDatabase.dbo.OrderLine'; column does not allow nulls. INSERT fails.


Solution

  • You can actually map the relationship only on one side, this shouldn't matter.

    Though the update statement will be executed in this case. To fix the exception, you'll just have to change the mapping to

    HasMany(x => x.OrderLines) 
      .AsBag() 
      .Cascade.AllDeleteOrphan() // or .All
       .KeyColumn("OrderId")
       .Not.KeyNullable();