1

This is supposed to be a simple 1-N relationship, however I am not able to save the children as NHibernate uses null as a value in the insert statement of the child.

 public class Event
 {
  public virtual string Id { get; set; }
  public virtual string Name { get; set; }        
  public virtual IList<EventParameter> Parameters{ get; set; }

  public Event() { Parameters = new List<EventParameter>(); }
 }

[Serializable]
public class EventParameter : Parameter
{
  public virtual Event Event { get; set; }
  public virtual string ComparisonMethod { get; set; }
  public override bool Equals(object obj) {}
  public override int GetHashCode() {}
}

The mappings are like this

public EventMapping()
{
    Table(...);

    Id(x => x.Id)
        .Column(...)
        .GeneratedBy
        .Custom<global::NHibernate.Id.SequenceGenerator>(builder => builder.AddParam("sequence", "...")); 

    Map(x => x.Name).Column("Name").Length(100);

    HasMany<EventParameter>(x => x.Parameters)
            .KeyColumns.Add(...)
            .Inverse()
            .Cascade.All();
}

public EventParameterMapping()
{
    Table(....);

    CompositeId()
        .KeyProperty(x => x.Event.Id, "...")
        .KeyProperty(x => x.ParameterId, "..."); 

    References(x => x.Event);          
}

The Insert statement for the parent is correct, however for the child it is not.

INSERT INTO ...
        (...columns...)
VALUES  (..., null, ...)

Before this happens I get the following warning: Unable to determine if entity is transient or detached; querying the database. Use explicit Save() or Update() in session to prevent this.

I do use Save() in the transaction. Any ideas why this happens?

1 Answers1

1

Solution here is suprisingly simply. We have to use inverse="true" mapping:

HasMany<EventParameter>(x => x.Children)
        .KeyColumns.Add("...")
        .Inverse()
        .Cascade.All();

But, this is kind of optimization, which would require both sides of relation to be always properly set in our C# code:

var parent = ...;
var child = new Child();
// both sides MUST be set
parent.Children.Add(child);
child.Parent = parent;

Please, observe this for more details

Inverse = “true” example and explanation

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • mmmm....I do not do this kind of circular reference in code. I shall try this now. Thanks for the suggestion. – Konstantinos Papakonstantinou Feb 17 '15 at 08:54
  • This "circular reference" is the HEART of the ORM. Object relational mapping. We map the relations. I found many disputations challenging this, but in my experience... if you do not want to have Business Domain Model expressed with [POCO (including relations)](http://stackoverflow.com/a/13632872/1679310)... do not use NHiberante (ORM)... But it is a bit larger topic... just... do ot worry to reference stuff. It is valid C# and valid ORM ;) – Radim Köhler Feb 17 '15 at 08:59
  • I removed the string ID property of the child and added a parent property and now i get an error that it cannot find a getter for an "Id" property. – Konstantinos Papakonstantinou Feb 17 '15 at 09:34
  • You should use surrogate key, synthetic for your child element. E.g. autogenerated column in SQL Server. This should be mapped to property Id. NO composite key, if possible. Anything else (while supported) will lead to many issues. Try to do it standard way (the realtion) as in doc: http://nhibernate.info/doc/nh/en/index.html#example-mappings. Maybe also please do read this: http://stackoverflow.com/a/28319725/1679310 – Radim Köhler Feb 17 '15 at 09:39
  • finally managed to get it right, but has been a pain. thanks a lot for your help. do you have any resources to recommend? – Konstantinos Papakonstantinou Feb 17 '15 at 12:25
  • Great to see that ;) I cannot remember one resource ;( Definitely try to observe Ayende's blog posts and SO ;) Good luck with NHibernate ;) – Radim Köhler Feb 17 '15 at 12:31