NHibernate returns id outside of session, but not through a property - nhibernate

I have an interface like this:
public interface ICoreType {
int TypeID {get;}
}
And an NHibernate class that implements it like this:
public class DueDateType : ICoreType {
public virtual int DueDateTypeID {get;set;}
...
public virtual int TypeID { get{ return this.DueDateTypeID; } }
}
Here's my mapping:
<class name="DueDateType" table="tdfDueDateType" lazy="true" >
<cache usage="read-write" include="all"/>
<id name="DueDateTypeID" column="DueDateTypeID" >
<generator class="identity"/>
</id>
...
</class>
When I get an instance of the object from NHibernate, and then return it outside the scope of the active session it was created in, I can get the value DueDateTypeID just fine, but accessing TypeID throws a LazyInitializationException. There is no mapping for TypeID, as I simply want it to return whatever DueDateTypeID's value is.
Marking the class lazy="false" in my mapping erases the problem. From what I've been reading, that is because there is no proxy generated for a non-lazy mapped class.
I would like to use the lazy loading features of NHibernate in this case; do I need to implement IInterceptor or some such, in order to get NHibernate to treat this property differently?

The problem is that all members of the entity trigger lazy initialization when accessed (except of the id). NH can't know what you actually are doing within the member. When triggering lazy initialization outside of the session, you get an error.
Suggestions:
Try to avoid any access to entities outside the session. It is only safe when turning off lazy loading - which is usually not a way to go.
Don't wrap the id. If you access TypeID, the entity is initialized although it is not necessary, which is bad for performance.

Related

NHIbernate lazy load a parent object

I have two objects, Case and Note. A Case can have gobs of Notes, like, in the thousands. We are trying to load them asynchronously, in batches, and stream them to the UI so there is no delay waiting for them all to load.
The class/mappings are
public class Case
{
public virtual IList<Note> Notes { get; protected set; }
}
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="SCMS.TAMS.BusinessEntities" namespace="SCMS.TAMS.BusinessEntities">
<class name="Case" table="Cases">
<bag name="Notes" inverse="true" cascade="all" lazy="true">
<key column="CaseID" />
<one-to-many class="Note" />
</bag>
</class>
</hibernate-mapping>
public class Note
{
public virtual Case Case {get; set;}
public virtual long CaseId {get; set;}
}
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="SCMS.TAMS.BusinessEntities" namespace="SCMS.TAMS.BusinessEntities" default-lazy="true">
<class name="Note" table="CaseNotes">
<many-to-one name="Case" column="CaseID"/>
<property name="CaseId" column="CaseID" />
</class>
</hibernate-mapping>
Now, when I call
NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Skip(0).Take(10).ToList();
to load the first 10 Notes for Case 123, the thing loads the Case object, which takes about 30 seconds because there's lots of other things on it, and other logic when it gets loaded, etc., none of which I need/want at this time. All I want/need are the 10 Notes.
I've tried all sorts of variations on this mapping and none of them have worked. What am I doing wrong here?
How are you using this query? is it some thing for the UI? liking showing in a grid or something? or are you performing business logic in a component?
Either way you want to project into another object. Your query right now returns a list of notes which is then going to load that parent object per the mappings.
So if you are using this query to send the information to the UI of an asp.net mvc application, project directly into your view model
NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Select(n => new SomeViewModel { Prop1 = n.Prop1, Prop2 = n.Prop2 ...}).Skip(0).Take(10).ToList();
or create an anonymous object
NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Select n => new { n.Prop1, n.Prop2, ...}).Skip(0).Take(10).ToList();
This will keep the parent object from loading. It also has the added benefit that you are only querying the information you need because the query be limited to the data you are projecting.
Important to know is that if all above is true...
this is the real mapping (which is not it is just an obvious extract)
<class name="Note" table="CaseNotes">
<many-to-one name="Case" column="CaseID"/>
...
this is the class (again extract without ID)
public class Note
{
public virtual Case Case {get; set;}
public virtual long CaseId {get; set;}
}
and that would be a UNIT TEST statement to load notes:
var list = NHibernateSession
.Query<Note>()
.Where(n => n.CaseId == 123)
.Skip(0).Take(10)
.ToList();
then NHibernate will NEVER load the Case object. Never. Because:
NHibernate is lazy, just live with it
The reason, the trigger to load related reference (Case property) must be something explicit.
Mostly:
there is usage of the Case object somewhere. E.g. in override of the GetHashCode() the Case.ID is used
Or:
there is a serialization or DTO conversion which does touch the Case property
In those case, NHibernate must load that...
So, create few unit tests with basic queries and assure that your the is really as shown above. Then it will work as expected

nhibernate composite-id with not existing key-many-to-one record

i have old legacy DB which has dead links in their tables. I have class mapped in nhibernate like this:
<class name="Visible" table="table_visible">
<composite-id>
<key-many-to-one column="object_id" name="ObjectA" />
<key-many-to-one column="sub_object_id" name="SubObject" />
</composite-id>
<property column="visible" name="VisibleRow" />
</class>
and:
public class Visible
{
public virtual ObjectAClass ObjectA { get; set; }
public virtual SubObjectClass SubObject { get; set; }
public virtual bool VisibleRow { get; set; }
public override bool Equals(object obj)
{
var other = ((Visible)obj);
return this.ObjectA.Equals(other.ObjectA) && this.SubObject.Equals(other.SubObject);
}
public override int GetHashCode()
{
return this.ObjectA.GetHashCode() + (this.SubObject != null? this.SubObject.GetHashCode(): 0);
}
}
Now all works fine when all joins in database are correct, but when i find such sub_object_id which doesnt have entity, nhibernate throws me error
No row with the given identifier exists:[SubObject#123]
Is there a way to map composite key so that when its subentity is not found, the whole entity wouldnt be loaded (like with inner join)?
NHibernate v2.0.50727
Following Daniel Schilling idea of fetch Visible entities with a where exists sub-query, found that there is loader element available in mappings.
<class name="ObjectA" table="table_object">
.........
<set name="VisibleList" cascade="all" lazy="false" inverse="true">
<key column="object_id" />
<one-to-many class="Visible" />
<loader query-ref="valid_entities"/>
</set>
</class>
<sql-query name="valid_entities">
<load-collection alias="v" role="ObjectA.VisibleList"/>
SELECT {v.*}
FROM table_visible v
INNER JOIN table_sub_entities e ON e.sub_entity_id=v.sub_entity_id
WHERE v.object_id=?
</sql-query>
And nothing else needed to be changed.
<key-many-to-one column="sub_object_id" name="SubObject" not-found="ignore" />
... may be helpful. From the NHibernate Documentation...
ignore will treat a missing row as a null association
Please be aware of the performance penalty associated with using this option. Whenever NHibernate fetches a Visible entity, it will also have to fetch SubObject. If you don't go ahead and fetch it in your query, this means that NHibernate will be issuing lots of lazy loads.
This doesn't meet your "when its sub-entity is not found, the whole entity wouldn't be loaded" goal. Instead NHibernate would give you an entity with a null sub-entity. If you want that inner-join-like behavior, then I think you would need to fetch your Visible entities with a where exists sub-query to make sure the SubObject actually exists.
The best option would be to fix the data in the database and add a foreign key constraint.
I just ran across this: Relations with not-found="ignore". I promise I'm not copying Ricci's content - I'm writing this from my own experience.

One-to-many relationship not saved

I've got this relationship between a ReportRow (parent) and a Mark (child)
<class name="ReportRow">
<bag name="Marks" cascade="save-update" inverse="true">
<key column="ReportRowId"/>
<one-to-many class="Mark"/>
</bag>
</class>
// C# code
public virtual IList<Mark> Marks { get; set; }
But it's not being saved (in the Mark table, ReportRowId is always null).
I know these relationships always have to be bidirectional because of the NHibernate 'quirk' so for my Mark class I have:
<many-to-one name="ReportRow" class="ReportRow" column="ReportRowId" />
// C#
public virtual ReportRow ReportRow { get; set; }
I've even got some other examples of this kind of relationship working elsewhere in my project, but this one isn't working and I can't see any difference apart from...
... both Mark and ReportRow both have subclasses (e.g. ModuleMark and ModuleReportRow), which I'm using the joined-subclass strategy to implement the inheritance.
Would that have something to do with it? For both ends of the relationship, the mappings are defined in the parent class mapping rather than nested inside the <joined-subclass> mappings.
Thanks
How are you adding Marks to the collection? Because the collection is the inverse side of the relationship, you need to set the reference to the parent object on the child when adding it to the collection. A common approach is to use methods in the parent object to maintain the relationship, e.g.:
public void AddMark(Mark mark)
{
mark.ReportRow = this;
Marks.Add(mark); // better yet map the collection as a private field
}
I think of "inverse" as "who wears the pants in this relationship".

Skipping an new/transient NHibernate entity's ID generator strategy when an ID is already provided

Just a quickie ... I have the following ID generator strategy for one of my mapped classes:
<id name="UID" type="System.Guid">
<column name ="UID" sql-type ="uniqueidentifier" />
<generator class="guid.comb" />
</id>
The entity in question is involved in synchronisation / merging behaviours from which it is necessary to have a globally unique identifier.
When an entity is created on a client application for the first time, it's UID property gets assigned so that it is the same value of the equivilent entity on the server.
However the above ID generator strategy overwrites any value provided for new/transient entities.
Whats the fix? Will I have to remove the generator strategy and assign my own GUIDs? Or is the generator strategy configurable to only generate a guid.comb when required?
I think you can accomplish this by making UID a private field and controlling access through the property.
public class MyClass
{
private Guid _uid;
protected MyClass() { // parameterless ctor for NH }
public MyClass(Guid uid) { _uid = uid; // assign on creation }
public Guid Uid
{
get { return _uid; }
private set { // do nothing or compare _uid to Guid.Empty and set }
}
}

NHibernate Collection Mapping - Read Only Properties

I have the following class
public class Person
{
private IList<Person> _children;
public IEnumerable<Person> Children { get; }
public void AddChild(Person child)
{
// Some business logic and adding to the internal list
}
}
What changes would I have to make for NHibenrate to be able to persist the Child collection (apart from making everything virtual, I know that one).
Do I have to add a setter to the children property which does something like a _children.Clear(); _children.AddRange(value). Currently the model expresses my intent quite nicely but I'm not sure how much alteration is need for NH to be able to help me out with persistence.
NHibernate is able to map private fields. Access and naming strategies are discussed in the property section of the reference documentation.
Making your public members virtual is required for proxies to work. These will usually be runtime-generated subclasses of your entity classes.
In this example mapping the field _children will be Children in HQL and Criteria queries.
<class name="Person" table="person">
<bag name="Children" access="field.camelcase-underscore">
<key column="parentid" />
<one-to-many class="Person" />
</bag>
</class>