2 posts that will probably help you http://nhforge.org/blogs/nhibernate/archive/2010/06/30/nhibernate-and-composite-keys.aspx
http://nhforge.org/blogs/nhibernate/archive/2011/01/08/composite-with-only-a-many-to-one-bad-idea.aspx John Davidson On Mon, Mar 28, 2011 at 11:46 AM, Hardy <[email protected]> wrote: > Hi all, > > In order to make myself clear, I have created a most basic case to > describe my problem. Let's say I have 3 tables: > > CREATE TABLE [dbo].[Product]( > [ProductID] [int] IDENTITY(1,1) NOT NULL, > [ProductName] [varchar](50) NOT NULL, > CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED ( [ProductID] ASC ) > ) ON [PRIMARY] > > CREATE TABLE [dbo].[OrderHeader]( > [HeaderID] [int] IDENTITY(1,1) NOT NULL, > [Comment] [varchar](100) NULL, > CONSTRAINT [PK_OrderHeader] PRIMARY KEY CLUSTERED ( [HeaderID] > ASC ) > ) ON [PRIMARY] > > CREATE TABLE [dbo].[OrderDetail]( > [HeaderID] [int] NOT NULL, /* FK to OrderHeader table */ > [ProductID] [int] NOT NULL, /* FK to Product table */ > [CreatedOn] [datetime] NOT NULL, > CONSTRAINT [PK_OrderDetail] PRIMARY KEY CLUSTERED > ( > [HeaderID] ASC, > [ProductID] ASC > ) > ) ON [PRIMARY] > > And I have created correponding entity classes and mapping classes. > > public class Product { > public virtual int? Id { get; set; } > > public virtual string Name { get; set; } > } > > public class ProductMap : ClassMap<Product> { > public ProductMap() { > Table("Product"); > > Id(x => x.Id, "ProductID").GeneratedBy.Identity(); > Map(x => x.Name, "ProductName"); > } > } > > public class OrderHeader { > public virtual int? Id { get; set; } > > public virtual string Comment { get; set; } > > public virtual IList<OrderDetail> Details { get; set; } > } > > public class OrderHeaderMap : ClassMap<OrderHeader> { > public OrderHeaderMap() { > Table("OrderHeader"); > > Id(x => x.Id, "HeaderID").GeneratedBy.Identity(); > Map(x => x.Comment, "Comment"); > > HasMany<OrderDetail>(x => > x.Details).KeyColumn("HeaderID").Inverse(); > } > } > > public class OrderDetail { > public virtual int? OrderHeaderId { get; set; } > > public virtual int? ProductId { get; set; } > > public virtual OrderHeader OrderHeader { get; set; } > > public virtual Product Product { get; set; } > > public virtual DateTime? CreatedOn { get; set; } > > public override bool Equals(object obj) { > OrderDetail other = obj as OrderDetail; > if (other == null) { > return false; > } else { > return this.ProductId == other.ProductId && > this.OrderHeaderId == > other.OrderHeaderId; > } > } > > public override int GetHashCode() { > return (OrderHeaderId.ToString() + "|" + > ProductId.ToString()).GetHashCode(); > } > } > > public class OrderDetailMap : ClassMap<OrderDetail> { > public OrderDetailMap() { > Table("OrderDetail"); > > CompositeId().KeyProperty(x => x.ProductId, > "ProductID").KeyProperty(x => x.OrderHeaderId, "HeaderID"); > > References<OrderHeader>(x => x.OrderHeader, > "HeaderID").Not.Nullable(); > References<Product>(x => x.Product, > "ProductID").Not.Nullable(); > > Version(x => > x.CreatedOn).Column("CreatedOn").Generated.Always(); > } > } > > I have also created NH Session Provider > > public class NHibernateSessionProvider { > private static ISessionFactory sessionFactory; > > public static ISessionFactory SessionFactory { > get { > if (sessionFactory == null) { > sessionFactory = > createSessionFactory(); > } > return sessionFactory; > } > } > > private static ISessionFactory createSessionFactory() { > return Fluently.Configure() > > .Database(MsSqlConfiguration.MsSql2008.ShowSql() > .ConnectionString(c => > c.FromConnectionStringWithKey("TestDB"))) > .Mappings(m => > m.FluentMappings.AddFromAssemblyOf<OrderHeaderMap>()) > .BuildSessionFactory(); > } > } > > And a NH repository class is also created > > public class NHibernateRepository<T, TId> { > protected ISession session = null; > protected ITransaction transaction = null; > > public NHibernateRepository() { > this.session = > NHibernateSessionProvider.SessionFactory.OpenSession(); > } > > public void Save(T entity) { > session.SaveOrUpdate(entity); > } > > public void AddNew(T entity) { > session.Save(entity); > } > > public void BeginTransaction() { > transaction = session.BeginTransaction(); > } > > public void CommitTransaction() { > transaction.Commit(); > closeTransaction(); > } > > public void RollbackTransaction() { > transaction.Rollback(); > closeTransaction(); > closeSession(); > } > > private void closeTransaction() { > transaction.Dispose(); > transaction = null; > } > > private void closeSession() { > session.Close(); > session.Dispose(); > session = null; > } > > public void Dispose() { > if (transaction != null) { > CommitTransaction(); > } > > if (session != null) { > session.Flush(); > closeSession(); > } > } > } > > In my code, I have created 2 different ways to save this master/detail > structure with composite-id. > > private static void method1() { > NHibernateRepository<OrderHeader, int?> repo = new > NHibernateRepository<OrderHeader, int?>(); > OrderHeader oh = new OrderHeader(); > oh.Comment = "Test Comment " + > DateTime.Now.ToString(); > oh.Details = new List<OrderDetail>(); > for (int i = 0; i < 2; i++) { > OrderDetail od = new OrderDetail > { > OrderHeader = oh, > Product = new Product > { > Id = i + 3 > } > }; > > oh.Details.Add(od); > } > > repo.Save(oh); > } > > private static void method2() { > NHibernateRepository<OrderHeader, int?> repoHeader = > new > NHibernateRepository<OrderHeader, int?>(); > OrderHeader oh = new OrderHeader(); > oh.Comment = "Test Comment " + > DateTime.Now.ToString(); > repoHeader.Save(oh); > > NHibernateRepository<OrderDetail, int?> repoDetail = > new > NHibernateRepository<OrderDetail, int?>(); > for (int i = 0; i < 2; i++) { > OrderDetail od = new OrderDetail > { > OrderHeaderId = oh.Id, > OrderHeader = oh, > ProductId = i + 3, > Product = new Product > { > Id = i + 3 > }, > }; > > repoDetail.AddNew(od); > } > } > > But for both methods, the OrderDetail table is never saved. I have > turned on ShowSql() to see SQL statement executed on console, no SQL > generated to save OrderDetail table at all. > > I did quite a lot of search everywhere and could not have a clear > conclusion what is wrong. > > Anybody has some clue, what exactly do I need to do to save an entity > with composite-id? > > Thanks > > Hardy > > -- > You received this message because you are subscribed to the Google Groups > "nhusers" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/nhusers?hl=en. > > -- You received this message because you are subscribed to the Google Groups "nhusers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.
