Fluent nhibernate m-to-m mapping with external table - nhibernate

I have two tables in Oracle
Entity
----------
**EntityId** NUMBER(9), **EntityName** VARCHAR2
EntityLinks
--------------
**EntityLinkId** NUMBER(9),**ParentEntityId** NUMBER(9), **ChildEntityId** NUMBER(9)
Table EntityLinks will store ManyToMany relationship between various entities. ParentEntityId and ChildEntityId are having foreign key relationship with Entity.
I have below a below class for Entity as well
public class Entity
{
public virtual int EntityId {get; set}
public virtual IList<Entity> ParentEntities {get; set}
public virtual IList<Entity> ChildEntities{get; set}
}
public class EntityLinks
{
public virtual int EntityLinkId {get; set}
public virtual Entity ParentEntityId {get; set}
public virtual Entity ChildEntityId {get; set}
}
Here is the mapping for both the classes:
public class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
Table("Entity")
Id(x=>x.EntityId).GeneratedBy.Increment();
*---- How to map for ParentEntities and ChildEntites?----*
}
}
public class EntityLinksMap : ClassMap<Entity>
{
public EntityMap()
{
Table("Entity")
Id(x=>x.EntityId).GeneratedBy.Increment();
References(x=>x.ParentEntityId).Column("ParentEntityId");
References(x=>x.ChildEntityId).Column("ChildEntityId");
}
}
My question is how should I do mapping in entity class for ParentEntities and ChildEntites so that I get the list of both parent and child for a particular entity?

I would say that it is really good, that you are using man-in-the-middle table as a standard mapped entity.
I am talking about the fact, that we can use mapping without that pairing table being represented as mapped entity. The syntax would be HasManyToMany
But because you've chosen to have pairing table as an entity you have to change the Business model:
public class Entity
{
public virtual int EntityId {get; set}
//public virtual IList<Entity> ParentEntities {get; set}
//public virtual IList<Entity> ChildEntities{get; set}
public virtual IList<EntityLinks> ParentEntityLinks {get; set}
public virtual IList<EntityLinks> ChildEntityLinks {get; set}
}
Mapping then would be:
public EntityMap()
{
Table("Entity")
Id(x=>x.EntityId).GeneratedBy.Increment();
HasMany(x => x.ParentEntityLinks)...
HasMany(x => x.ChildEntityLinks)...
}
More about HasMany mapping:
Mapping-by-Code - Set and Bag by Adam Bar
Scroll down to Fluent NHibernate's equivalent:
HasMany(x => x.Users)
.AsSet<CustomComparer>() // or .AsSet(), .AsBag()
.Fetch.Join()
.BatchSize(100)
.LazyLoad() // or .ExtraLazyLoad()
.Table("tableName")
.Schema("schemaName")
.Cascade.AllDeleteOrphan() // or .None(), .SaveUpdate(), .All(), DeleteOrphan()
.Inverse()
...
// and many more settings
...
If in fact, you really want to keep the many-to-many, and properties like
public virtual IList<Entity> ParentEntities {get; set}
public virtual IList<Entity> ChildEntities{get; set}
The mapping will be
HasManyToMany(x => x.ParentEntities)...
HasManyToMany(x => x.ChildEntities)...
...which I would not suggest to use: How to create NHibernate HasManyToMany relation or Nhibernate: How to represent Many-To-Many relationships with One-to-Many relationships?, Here are some more details how to use HasManyToMany if ...

I figured out the mappings to be use. I was just confused in the problem at hand since this is self-referencing.
public class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
Table("Entity")
Id(x=>x.EntityId).GeneratedBy.Increment();
//solution mapping
HasManyToMany(x => x.ChildEntities)
.Table("EntityLinks")
.ParentKeyColumn("ParentEntityId")
.ChildKeyColumn("ChildEntityId");
HasManyToMany(x => x.ParentEntities)
.Table("EntityLinks")
.ParentKeyColumn("ChildEntityId")
.ChildKeyColumn("ParentEntityId");
}
}
public class EntityLinksMap : ClassMap<EntityLinks>
{
public EntityMap()
{
Table("EntityLinks")
Id(x=>x.EntityId).GeneratedBy.Increment();
References(x=>x.ParentEntityId).Column("ParentEntityId");
References(x=>x.ChildEntityId).Column("ChildEntityId");
}
}

Related

Map list of items

I have a table called openTickets. I have another table called openTicketFollowers that relates to it using a foreign key. OpenTickets does not know about openTicketFollowers but I want openTickets to have a property that is a list of its followers. Is there anyway to do this with fluent nhibernate?
Check this Fluent mapping document. The OpenTicket class will contain IList of Followers:
public class OpenTicket
{
...
public virtual IList<OpenTicketFollower> Followers { get; set; }
}
public class OpenTicketFollowers
{
public virtual OpenTicket OpenTicket { get; set; }
}
And this is fluent mapping of the OpenTicketFollowercollection:
HasMany(x => x.Followers)
.KeyColumn("OpenTicketId");
and the OpenTicketFollower class mapping referencing the OpenTicket
References(x => x.OpenTicket)
.Column("OpenTicketId")

Fluent NHibernate insert parent id problem with HasMany relationship

I can't understand why NHibernate is inserting a child entity without the foreign key of the parent.
The only way I found to solve this is with a Bidirectional relationship, is there another way?
Here are the classes:
public class Parent
{
public virtual int ParentId {get; private set;}
public virtual IList<Child> Notes {get; private set;}
}
public class Child
{
public virtual ChildId {get; private set;}
public virtual Name {get; private set;}
}
Here is my Fluent NHibernate mapping
public class ParentClassMap : ClassMap<Parent>
{
public ParentClassMap(){
Id(x => x.ParentId);
HasMany(x => x.Notes).Cascade.AllDeleteOrphan();
}
}
public class ChildClassMap : ClassMap<Child>
{
public ChildClassMap() {
Id(x => x.ChildId);
Map(x => x.Name);
}
}
When I add a child to the parent's child collection and save the parent, the parent and the child are inserted into the database, but the child is inserte withoutthe foreign key to the parent (it has a null value)
This is the insert that is generated:
INSERT INTO Child(ChildId, Name)
But it should be:
INSERT INTO Child(ChildId, Name, ParentId)
I want to add that i don't want to resolve this with a bidirectional relationship, i do not want the child to have a reference to the parent. Thanks!!
Add Not.KeyNullable() to your HasMany mapping.
Note: This feature requires NHibernate 3.2.
Your parent class mapping should have an inverse for its child
public class ParentClassMap : ClassMap<Parent>
{
public ParentClassMap(){
Id(x => x.ParentId);
HasMany(x => x.Notes).Cascade.AllDeleteOrphan().Inverse();
}
}
Thanks
Neelesh

How to only get the Ids from a FluentNhibernate HasManyToMany mapping

Say I have two Entities.
public class Category{
public virtual int Id{get;set;}
public virtual IList<Post> Posts{get;set;}
}
public class Post{
public virtual int Id{get;set;}
public virtual string Title{get;set;}
}
In the Db there's a many-to-many table
CategoryPostRel
CategoryId
PostId
The category Map then looks like this:
public CategoryMap()
{
HasManyToMany(x => x.Posts)
.Table("CategoryPostRel")
.ParentKeyColumn("CategoryId")
.ChildKeyColumn("PostId");
}
Ok, but say I only want the Ids from the Posts. So I change my Category entity to look like this.
public class Category{
public virtual int Id{get;set;}
public virtual IList<int> PostIds{get;set;}
}
So now, how do I get the ids with my mapping as the HasManyToMany maps Entities, not columns right?
Note that I can't change the db at all and the many-to-many table has no unique identifier.
public CategoryMap()
{
HasManyToMany(x => x.PostIds)
.Table("CategoryPostRel")
.ParentKeyColumn("CategoryId")
.ChildKeyColumn("PostId").HowDoIgetTheIds...?
}
You could create an entity that models this relationship CategoryPost and do something like this:
public CategoryMap()
{
HasMany(x => x.CategoryPostIds)
.KeyColumn("CategoryId")
}
public CategoryPostMap
{
CompositeId()
.KeyProperty(x => x.PostId)
.KeyProperty(x => x.CategoryId)
}
This is obviously not an ideal solution but it may work.

self referemce many to many nhibernate mapping convention

public class Node
{
public virtual int Id {get; set;}
public virtual string Name {get; set;}
public virtual IList<Node> Ancestors {get; set;}
public virtual IList<Node> Descendants {get; set;}
}
how to setup the mapping convention for this case?
thank you
Are you sure you want a convention? I am going to guess you just want a fluent mapping. Here's an example from the last time I helped someone with this:
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.CustomerId);
Map(x => x.Birthday);
Map(x => x.FirstName);
HasManyToMany(x => x.Parents)
.ParentKeyColumn("ChildID")
.ChildKeyColumn("ParentID")
.Inverse();
HasManyToMany(x => x.Children)
.ParentKeyColumn("ParentID")
.ChildKeyColumn("ChildID");
}
}
See here for the original thread. That thread has a link to an example project I made for demonstrating self referencing many-to-many relationships, which is here.

Fluent NHibernate: How to create one-to-many bidirectional mapping?

Basic question: How to I create a bidirectional one-to-many map in Fluent NHibernate?
Details:
I have a parent object with many children. In my case, it is meaningless for the child to not have a parent, so in the database, I would like the foreign key to the parent to have NOT NULL constraint. I am auto-generating my database from the Fluent NHibernate mapping.
I have a parent with many child objects like so:
public class Summary
{
public int id {get; protected set;}
public IList<Detail> Details {get; protected set;}
}
public class Detail
{
public int id {get; protected set;}
public string ItemName {get; set;}
/* public Summary Owner {get; protected set;} */ //I think this might be needed for bidirectional mapping?
}
Here is the mapping I started with:
public class SummaryMap : ClassMap<Summary>
{
public SummaryMap()
{
Id(x => x.ID);
HasMany<Detail>(x => x.Details);
}
}
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Id(x => x.ID);
Map(x => x.ItemName).CanNotBeNull();
}
}
In the Detail table, the Summary_id should be Not Null, because in my
case it is meaningless to have a Detail object not attached to the
summary object. However, just using the HasMany() map leaves the Summary_id foreign key nullable.
I found in the NHibernate docs (http://www.hibernate.org/hib_docs/nhibernate/html/collections.html) that "If the parent is required, use a bidirectional one-to-many association".
So how do I create the bidirectional one-to-many map in Fluent NHibernate?
To get a bidirectional association with a not-null foreign key column in the Details table you can add the suggested Owner property, a References(...).CanNotBeNull() mapping in the DetailsMap class, and make the Summary end inverse.
To avoid having two different foreign key columns for the two association directions, you can either specify the column names manually or name the properties in a way that gives the same column name for both directions. In this case you I suggest renaming the Details.Owner property to Details.Summary.
I made the Summary id generated by increment to avoid problems when inserting into the table since Summary currenty has no columns besides id.
Domain:
public class Detail
{
public int id { get; protected set; }
public string ItemName { get; set; }
// Renamed to use same column name as specified in the mapping of Summary.Details
public Summary Summary {get; set;}
}
public class Summary
{
public Summary()
{
Details = new List<Detail>();
}
public int id { get; protected set; }
public IList<Detail> Details { get; protected set; }
}
Mapping:
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Id(x => x.id)
.GeneratedBy.Native();
Map(x => x.ItemName)
.CanNotBeNull();
References<Summary>(x => x.Summary)
// If you don't want to rename the property in Summary,
// you can do this instead:
// .TheColumnNameIs("Summary_id")
.CanNotBeNull();
}
}
public class SummaryMap : ClassMap<Summary>
{
public SummaryMap()
{
Id(x => x.id)
.GeneratedBy.Increment();
HasMany<Detail>(x => x.Details)
.IsInverse()
.AsBag(); // Use bag instead of list to avoid index updating issues
}
}