I have many NH entities that use non generic list. (using generic="false" and IList)
I have downloaded NH4 and noticed that NH4 does not support persisting non generic list. While saving I got this exception :
Unable to cast object of type 'System.Collections.ArrayList' to type
'System.Collections.Generic.IEnumerable`1[System.Object]'.
Is there any simple solution to upgrade my NH entities?
public virtual IList TemplateProperties
{
get
{
return this._TemplateProperties;
}
set
{
this._TemplateProperties = value;
}
}
<bag name="TemplateProperties" generic="false">
<key>
<column name="PRPT_ID" not-null="true" precision="10" scale="0" sql-type="int" />
</key>
<one-to-many class="TemplateProperty" />
</bag>
change the implementation of the models to use generic lists. They are still handed out as IList
private readonly List<object>_TemplateProperties = new List<object>();
public virtual IList TemplateProperties
{
get { return this._TemplateProperties; }
}
Then specify in the mapping to use the field instead of the property access the value
<bag name="TemplateProperties" access="field.pascalcase-underscore">
Related
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.
Why can't NHibernate access a property inherited from an abstract base class. When I try to use the property in a QueryOver in the Where clause I'm getting
could not resolve property: ID of: TheWorkshop.Web.Models.Customer
var customer = Session.QueryOver<Customer>()
.Where(c=>c.ID ==id)
.SingleOrDefault<Customer>();
Intelisense helped me build the query and the solution compiles, so there is an ID property on the Customer class. The ID property on Customer is inherited from an abstract Contact class that in turn inherits from a DomainEntity<T> which exposes a protected field.
public abstract class DomainEntity<T>
{
protected Guid _persistenceId;
//...
}
public abstract class Contact : DomainEntity<Contact>
{
public virtual Guid ID
{
get { return _persistenceId; }
}
public virtual Address Address
{
get { return _address; }
set { _address = value; }
}
//...
}
and in the mapping file
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="TheWorkshop.Web"
namespace="TheWorkshop.Web.Models"
default-access="field.camelcase-underscore"
default-lazy="true">
<class name="Contact" table="Contacts" abstract="true">
<id name="_persistenceId" column="ID" type="Guid" access="field"
unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb" />
</id>
<!-- ... -->
<union-subclass name="Customer" table="Customers">
Following the answer to a similar question I updated to NHibernate 3.3.3-CR1 from NHibernate 3.3.2.4000 but I still have the same issue.
The problem was that NHibernate couldn't infer from my mapping how to resolve the ID property. So although the classes compiled fine and the _persistenceId property on the abstract base class could be accessed through a getter on the implementing classes, because of the mismatch in names between _persistenceId and ID NHibernate wasn't able to follow that.
The (easier) solution was to change my names to match up. There is a harder solution which involves implementing the IProperyAccessor, IGetter and ISetter interfaces and in order to provide a path to pass the string ID in order to use the ClassName access strategy.
The simpler of the two solutions was just to rename _persistenceId to _id (and update all the references to it) so
<id name="_persistenceId" column="ID" type="Guid" access="field"
unsaved-value="00000000-0000-0000-0000-000000000000">
becomes
<id name="Id" column="Id" type="Guid"
unsaved-value="00000000-0000-0000-0000-000000000000">
Note I was also able to drop the access="field" in the updated id mappings
I have a bidirectional relationship in NHibernate:
<class name="Child" table="Children">
<many-to-one name="Parent" column="ParentId" not-null="true" />
</class>
<class name="Parent">
<set name="Children" lazy="true" table="Children" cascade="all">
<key column="ParentId" not-null="true" />
<one-to-many class="Child" />
</set>
</class>
How do I save it without setting inverse="true" and setting Parent property on Child?
I do not want to do this because it does not make much sense from the POCO perspective.
Alternatively, is it possible to intercept Add called on NHibernate proxy collection (Children)?
In that case, I would just put the Parent setting logic here.
Unless you're willing to make the foreign key nullable and accept an insert followed by an update, that's the way bidirectional one-to-many works in NHibernate.
I do have a generic implementation of this pattern that you can use... it's a proof of concept; it can be useful or not, depending on how you look at it, as it kinda breaks the POCO approach, but... well, here it is:
public interface IHaveParent<T>
{
T Parent { get; set; }
}
public interface IHaveMany<T>
{
ICollection<T> Children { get; }
}
public static class OneToManyHelper
{
public static void AddChild<TParent, TChild>(this TParent parent,
TChild child)
where TChild : IHaveParent<TParent>
where TParent : IHaveMany<TChild>
{
parent.Children.Add(child);
child.Parent = parent;
}
}
With this, you can all AddChild on any parent.
The problem with intercepting Add calls is that you'd always need to instantiate your collections using a special method (which, again, is not POCO).
I have an odd problem in my current project. Lazy loading for queries does not work. When I query a list, nhibernate fetches all associations separately.
I extracted small parts of it and put it into a separate solution. Basically what I've got now, is a Account-Table and a AccountSync-Table. Both have an ID and a URL, while the ID is just a db-guid.
My classes are:
public class HippoAccount
{
public virtual Guid Id { get; set; }
public virtual string Url { get; set; }
public virtual HippoAccountSync Sync { get; set; }
}
public class HippoAccountSync
{
public virtual Guid Id { get; set; }
public virtual string Url { get; set; }
public virtual HippoAccount Account { get; set; }
}
When I now load a object via it's guid:
var account = session.Load<HippoAccount>(accountId);
Console.WriteLine(NHibernateUtil.IsPropertyInitialized(account, "Sync"))
... it returns false and account itself is a proxy.
But when loading a list via the criteria API:
var account = (HippoAccount)session
.CreateCriteria(typeof (HippoAccount))
.Add(Restrictions.Eq("Id", accountId))
.List()[0];
... the property Sync gets initialized (firing a second select query), and the returned object is not a proxy.
Is that default behaviour? What am I getting wrong?
The mapping is:
<class name="HippoAccount" table="AllAccounts">
<id name="Id" type="guid">
<generator class="guid"/>
</id>
<property name="Url" />
<many-to-one
class="HippoAccountSync"
name="Sync"
not-found="ignore"
property-ref="Url">
<column name="url" />
</many-to-one>
</class>
<class name="HippoAccountSync"
mutable="false"
table="Accounts">
<id name="Id" type="guid">
<generator class="guid"/>
</id>
<property name="Url">
<column name="serviceUri" />
</property>
<many-to-one class="HippoAccount"
name="Account"
property-ref="Url"
not-found="ignore">
<column name="serviceUri" />
</many-to-one>
</class>
After quite some more research, I found the answers. Answers, because there are many things that can prevent lazy loading in NHibernate.
Query vs. session.Load: When fetching an item via session.Load() you get a proxy. But as soon as you access any property, lets say the Url, the object is fetched including all it's associations that doesn't support lazy loading.
property-ref: Lazy loading only works over a objects id. When an property-association is resolved via a different column in the target entity, NH fetches it eagerly. Not that this wouldn't be possible, it's just not implemented: Bug
not-found="ignore" allows invalid foreign keys, that is, if the referenced entity isn't found NH will init the property with null. NH doesn't intercept the property-access for lazy loading, but instead assignes a object proxy. With not-found="ignore" it can't decide if the property should be set to null or a proxy for the given, possibly invalid, foreign key. This could possibly be solved by intercepting the property access.
When disabling not-found="ignore" and property-ref the schema export would generate constraints that enforce a circular reference. Not good! The correct mapping would then be a constrained one-to-one relationship, where the key for HippoAccountSync must have a generator foreign.
Resources
Select statement issued for each not-found=ignore
Lazy-load conflicts with Property-ref in Many-to-One Mapping
Google groups discussion
I have a data structure which uses composite ids (Which I dont wish to change to single)
Everything loads fine except for many-to-one joins which if the join is empty, instead of mapping the property to null, maps it to an empty proxy object. I have written an ugly work around( see bleow). Any solutions to this?
private Node _Parent;
public Node Parent
{
get
{
return this._Parent;
}
set
{
this._Parent = Proxy.Check<Node>(value);
}
}
internal static class Proxy
{
public static T Check<T>(T obj) where T : PersistentObject
{
if (obj is NHibernate.Proxy.INHibernateProxy && obj != null)
{
try
{
int id = obj.ID;
return obj;
}
catch //Proxy only object cant retrieve ID
{
return null;
}
}
else
{
return obj;
}
}
}
with the mapping file beginning
<class name="Node" table="Node">
<composite-id>
<key-property name="ID"/>
<key-property name="VersionID"/>
</composite-id>
and accessed by
<many-to-one name="Node" class="Node" >
<column name="NodeID"/>
<column name="VersionID" />
</many-to-one>
Not exactly sure if this is the perfect fix for this situation, but this fixed the issue for me when I encountered the same problem while working on an old DB with composite keys.
By setting not-found to ignore on your links, NHibernate will treat empty objects as null instead of exceptions. When using this technique NHibernate will execute a seperate query so there may be small performance hits, as this is basically eager loading the object.
You could try just eager loading the object instead of using this technique, but I have a feeling it would return an exception as it would be expecting an object (not null). I would suggest posting a question in the NHibernate forums if this doesn't work as I am definately not an expert in this area, but this may be a smaller/less ugly work around for you.
For example:
<many-to-one name="Node" class="Node" not-found="ignore">
<column name="NodeID"/>
<column name="VersionID" />
</many-to-one>
Hope this helps,
Jay