NHibernate Mapping - many-to-one via table - nhibernate

I'm working with an existing database that has the following structure. Changing the database schema is a last resort.
Products
Id
Name
ParentProducts
ParentId
ChildId
I don't want an entity for ParentProducts, I have the following for the children property (still need to test it, but that's the concept).
<bag name="Children" lazy="true" table="dbo.ParentProducts" cascade="save-update" inverse="true" >
<key column="[ChildId]"></key>
<many-to-many column="[ProductId]" class="Product" />
</bag>
What I'm struggling with is how do I create a Parent property? I'd like to do something like the following, but table isn't a valid attribute for many-to-one.
<many-to-one name="Parent" column="[ParentId]" table="dbo.ParentRelated" class="Policy" />
I could create a bag and only ever look at the first item, but that's more of a hack.
Any ideas?
Thanks

Creating a bag is the easiest solution. And you can give it a clean interface:
protected virtual ICollection<Product> Parents { get; set; }
public virtual Product Parent
{
get
{
return Parents.SingleOrDefault();
}
set
{
Parents.Clear();
Parents.Add(value);
}
}
With this, the rest of the code doesn't need to be aware of the DB/mapping structure.

Related

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.

nhibernate many-to-one parent is always null on insert

I am using NHibernate 3.1.0.4000 and AutoMapper 2.0.0.0 in a WCF. I have a parent-child relationship I want to maintain from the "many" end. I have no problems maintaining the objects if I do it from the "one" end but in this case that does not make sense. My issue is no matter how I change my mappings, POCOs, etc. the parent object when I attempt to add a child is null in the child causing the insert to fail. What am I missing to get the parent property in the child to populate?
I have a parent-child relationship defined in the following tables:
Create Table Attribute (AttributeUID uniqueidentifier, LongName varchar(20))
Create Table AnswerOption (AnswerOptionID int, AttributeUID uniqueidentifier)
I want the Attribute (parent) to be the owner so I declare the relationship in that mapping file and not in the AnswerOption (child). Though, I have tried with having the relationship bidirectional as well and that has not changed any behaviors in my tests. My mappings apear as follows. Attribute:
<class name="RCAttribute" table="rcs.tblAttribute">
<cache usage="read-write"/>
<id name="ID">
<column name="AttributeUID" />
<generator class="guid" />
</id>
<property name="LongName" type="string" not-null="true" length="200" column="LongName" />
<bag name="AnswerOptions" lazy="true" inverse="true" cascade="all">
<key column="AttributeUID"/>
<one-to-many class="AnswerOption" />
</bag>
</class>
AnswerOption:
<class name="AnswerOption" table="rcs.tblAnswerOption" lazy="true">
<cache usage="read-write"/>
<id name="ID">
<column name="AnswerOptionID" />
<generator class="native" />
</id>
</class>
Attribute Class:
[Serializable]
public class RCAttribute
{
public virtual Guid ID { get; set; }
public virtual string LongName { get; set; }
public virtual ICollection<AnswerOption> AnswerOptions { get; set; }
public RCAttribute() { ID = new Guid("00000000-0000-0000-0000-000000000000"); }
}
AnswerOption Class:
[Serializable]
public class AnswerOption
{
public virtual int ID { get; set; }
public AnswerOption() { ID = 0; }
}
My test procedure looks like this;
public void CreateAnswerOption()
{
AnswerOption newOpt = new AnswerOption();
Attribute.AnswerOptions.Add(newOpt);
Attribute = rc.RCAttributeSave(Attribute);
}
When it goes to create this the Attribute property of the AnswerOption is null so it cannot insert since the parent cannot be null in the child in this case. What am I missing to get it to populate the parent property on the child and be able to insert?
Mapping the collection as inverse without mapping the many-to-one on the other side makes no sense.
You have three options:
Use a bidirectional mapping with inverse="true" on the collection side and set the many-to-one propery (parent reference) in your code before saving the child (yes, I read that you don't want to do it that way).
Only map the collection side (not inverse). NHibernate will then first insert the child with NULL as parent reference, but will update it with the correct parent ID in the same transaction. So you can't have a not null constraint on the parent ID column in the child table (at least it must be deferrable).
(This option only works with NHibernate 3.2.0 or newer) Same as option 2, but add not-null="true" to the key tag in the collection mapping. Then NHibernate will insert the child with the parent ID already set.

NHibernate - Mapping tagging of entities

I've been wrecking my mind on how to get my tagging of entities to
work. I'll get right into some database structuring:
tblTag
TagId - int32 - PK
Name
tblTagEntity
TagId - PK
EntityId - PK
EntityType - string - PK
tblImage
ImageId - int32 - PK
tblBlog
BlogId - int32 - PK
class Image
Id
EntityType { get { return "MyNamespace.Entities.Image"; }
IList<Tag> Tags;
class Blog
Id
EntityType { get { return "MyNamespace.Entities.Blog"; }
IList<Tag> Tags;
The obvious problem I have here is that EntityType is an identifer but
doesn't exist in the database. If anyone could help with the this
mapping I'd be very grateful.
You don't need the entity type. Take a look at any-type mapping (it stores the type name in the database in the relation table, but you don't need it in the entity model).
See this blog post by ayende.
Edit: tried to write an example.
You could have an own table for each tagged object, this is easy and straight forward, you don't even need any types:
<class name="Tag">
<!-- ... -->
<property name="Name"/>
</class>
<class name="Image">
<!-- ... -->
<bag name="Tags" table="Image_Tags">
<key column="Image_FK"/>
<many-to-many class="Tag" column="TagId "/>
</bag>
</class>
Tried to use some advanced features to map it into a single table, but I think it doesn't work this way:
<class name="Tag">
<!-- ... -->
<property name="Name"/>
<bag name="Objects" table="tblTagEntity" access="noop">
<key column="TagId"/>
<many-to-any id-type="System.Int64" meta-type="System.String">
<meta-value
value="IMAGE"
class="Image"/>
<meta-value
value="BLOG"
class="Blog"/>
<column name="EntityType"/>
<column name="EntityId"/>
</many-to-any>
</bag>
</class>
<class name="Image">
<!-- ... -->
<bag name="Tags" table="tblTagEntity" where="EntityType='IMAGE'">
<key column="EntityId"/>
<many-to-many class="Tag" column="TagId "/>
</bag>
</class>
The tricks here are:
access="noop" to specify the foreign key without having a property in the entity model, see this post.
where="EntityType='IMAGE'" to filter the loaded data.
The problem is that most probably the EntityType is not set to any useful value. This could be fixed somewhere, but I don't think that it is worth the effort.
Someone else has probably a better idea.
Edit 2: another (working) solution
make the association table an entity:
in short:
Tag => TagEntity: not mapped or one-to-many inverse (noop)
TagEntity => Tag: many-to-one
TagEntity => Object: any
Object => TagEntity: one-to-many inverse
This should work straight forward.
classes:
class Tag
{
string Name { get; set; }
}
class TagEntity
{
Tag Tag { get; set; }
object Entity { get; set; }
}
class Image
{
IList<TagEntity> tags { get; private set; }
}
The only drawback seems to be that you have to make sure that the bidirectional associations are consistent without loading to much data. Note that inverse collections are not stored.
Edit 2: Performance notes
When you add / remove tags, you could do a trick. TagEntity has a reference to the tagged entity. The Entity also has a list of TagEntities, but this is marked as inverse. (This means, they are loaded, but not stored.)
You can add and remove tags without loading the Entity an without loading all the tags.
Adding:
Get Tag to add (or load proxy if you have the id of the tag)
Load Entity (just proxy, using session.Load, no db access here)
create new TagEntity, assign tag and entity-proxy
save TagEntity
Removing:
Get TagEntity to remove
delete TagEntity.
Within the session, you don't have this tag assigned to/removed from the TagEntity. This works fine assumed that you only add or remove tags within this transaction.
I you define a list of TagEntities on the Tag, you can do the same, without loading all the TagEntities just to add or remove one.
You could make EntityType an Enum in your code. And/or, you could try making EntityType an actual entity in your database (tblEntityType).
Got Stefans final solution to work! Here's my final mappings:
Image
<bag name="TagEntites" table="tblTagEntity" cascade="all" fetch="join" inverse="true" where="EntityType='EntityImage'">
<key column="EntityId"></key>
<one-to-many class="TagEntity" />
</bag>
TagEntity
<id name="Id">
<column name="TagEntityId"></column>
<generator class="identity" />
</id>
<any name="Entity" id-type="System.Int32" meta-type="System.String">
<meta-value value="EntityImage" class="Image" />
<column name="EntityType"></column>
<column name="EntityId"></column>
</any>
<many-to-one name="Tag" class="Tag" cascade="all" fetch="join">
<column name="TagId"></column>
</many-to-one>

many-to-many mapping in NHibernate

I'm looking to create a many to many relationship using NHibernate. I'm not sure how to map these in the XML files. I have not created the classes yet, but they will just be basic POCOs.
Tables
Person
personId
name
Competency
competencyId
title
Person_x_Competency
personId
competencyId
Would I essentially create a List in each POCO for the other class? Then map those somehow using the NHibernate configuration files?
You can put the many-to-many relation to either class, or even to both. This is up to your domain model. If you map it to both, one of them is inverse.
class Person
{
// id ...
IList<Competency> Competencies { get; private set; }
// you domain model is responsible to manage bidirectional dependencies.
// of course this is not a complete implementation
public void AddCompetency(Competency competency)
{
Competencies.Add(competency);
competency.AddPerson(this);
}
}
class Competency
{
// id ...
IList<Person> Persons { get; private set; }
}
Mapping:
<class name="Person">
<id ....>
<bag name="Competencies" table="Person_x_Competency">
<key column="personId"/>
<many-to-many class="Competency" column="competencyId"/>
</bag>
</class>
<class name="Competency">
<id ....>
<bag name="Persons" table="Person_x_Competency" inverse="true">
<key column="competencyId"/>
<many-to-many class="Person" column="personId"/>
</bag>
</class>
Only make it bidirectional if you really need it.
By the way: it is much better to write the classes first and create the database design afterwards. The database can be exported from the mapping files. This is very useful.

How do I map List<List<EntityClass>> in NHibernate?

I have a Rotation class, which contains references to multiple lists of Advert objects. I would prefer an implementation where Rotation has a property of type List<List<Advert>> to hold these, but I am unable to come up with an NHibernate mapping supporting this.
In the database schema, the many-to-many relation between Rotation and Advert is represented as a table RotationAdvert with the following columns:
RotationID
AdvertID
Variant ("horizontal position" / index within outer list)
Position ("vertical position" / index within inner list)
The best solution I have found yet, is to implement a fixed number of List<Advert> typed properties on Rotation and extend the mapping with a <list> element for each:
<list name="Variant1" table="RotationAdvert" where="Variant = 1">
<key column="RotationID"/>
<index column="Position"/>
<many-to-many class="Advert" column="AdvertID"/>
</list>
<list name="Variant2" table="RotationAdvert" where="Variant = 2">
<key column="RotationID"/>
<index column="Position"/>
<many-to-many class="Advert" column="AdvertID"/>
</list>
etc...
However, this requires me to specify a fixed number of variants, which I really would like to avoid.
What are my other options? Can I squeeze a RotationVariant class into the model - without creating new tables in the database - and somehow map a List<RotationVariant> property on Rotation? Or will I have to create a new table in the database, just to hold an ID for each RotationVariant?
I just ran into this same problem today. Reading through the Hibernate documentation and found an answer in section 6.1: Collection Mapping https://www.hibernate.org/hib_docs/nhibernate/html/collections.html:
Collections may not contain other collections
I couldn't find this exact sentence in the NHibernate docs, but it seems that the same rule applies. Like Stephan and Chris said, you will probably need to have another entity to hold the values.
The best I can think of is to adapt the model to the desired database structure.
class Rotation
{
IList<AdvertVariant> AdvertVariants { get; private set; }
}
class AdvertVariant
{
int Variant { get; set; }
Advert Advert { get; set; }
}
mapping:
<class name="Rotation">
<list name="AdvertVariants" table="RotationAdvert" >
<key column="RotationID"/>
<index column="Position"/>
<one-to-many class="AdvertVariant"/>
</list>
</class>
<class name="AdvertVariant">
<property name="Variant" />
<many-to-one name="Advert" column="VariantId"/>
</class>
Database:
Rotation:
id
AdvertVariant
id
Variant
RotationId
VariantId
Advert
id
Then you can easily create properties like this:
class Rotation
{
//...
IDictionary<int, IList<Adverts>> AdvertsByVariant
{
return VariantAdverts.ToDictionary(x => x.Variant, y => y.Advert);
}
}
I'd propose to have a Rotation class which holds a list of Adverts. An advert then holds a list of child adverts in a parent child relationship.