How to only get the Ids from a FluentNhibernate HasManyToMany mapping - nhibernate

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.

Related

Fluent nhibernate m-to-m mapping with external table

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");
}
}

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 and per-subclass inheritance

I have a Base class and two childs (A:Base and B:Base), and I want to map them to two tables (table A and table B). Is that possible in Fluent NHibernate? So I have:
public class Base
{
public virtual int Id {get;set;}
public virtual int IndexIn {get;set;}
public virtual Product Product {get;set;}
}
public class A : Base
{
public virtual string Value {get;set;}
}
public class B : Base
{
public virtual int Value {get;set;}
public virtual IList<Sequence> Sequences {get;set;}
}
My mapping is:
public class BaseMap : ClassMap<Base>
{
public BaseMap()
{
Id(x => x.Id);
Map(x => x.IndexIn);
References(x => x.Product);
}
}
public class AMap : SubclassMap<A>
{
public AMap()
{
Map(x => x.Value);
}
}
public class BMap : SubclassMap<B>
{
public BMap()
{
Map(x => x.Value);
HasMany(x => x.Sequences);
}
}
But in that case it creates three tables (A, B and Base). That's nice, but I need to reduce number of tables, so I am ok to have Base's fields in both A and B table. Generally I want to simply map A and B as normal classes (without using inheritance), but I need to be able to add some other class, where I can have property:
public virtual IList<Base> ListofAandB {get;set;}
If I remove BaseMap definition and just map A and B as ClassMap<> I receive error "Cannot find map definition for Base" if I try to use the property that is written above.
You won't be able to map your ListOfAAndB property if your inheritance is present only in your code and not in your database model. To have NHibernate map this property as it is defined, you are going to need a Base table in your database.

Fluent nHibernate mapping opposite side of References

I've got a table structure similar to the below:
AttributeKey (ID, Title)
AttributeValue (ID, AttributeKeyID, Value)
I've got my mapping all setup so that if I query AttributeValue, it joins to AttributeKey (AttributeValue.AttributeKeyID = AttributeKey.ID) using References, no problem... however, I want to query the AttributeKey table and LEFT JOIN onto the AttributeValue table so that I get all AttributeKeys and any values ascociated to them... how do I map this in fluent nHibernate?
Essentially it's the reverse of a References mapping.
EDIT: I'm aware that the HasMany method is meant to be the reverse of References but using that throws the exception that my property doesn't implement UserCollectionType
Cheers
This should be a HasMany in your AttributeKey ClassMap. Your class should look something like this:
public class AttributeKey
{
public int Id { get; set; }
public string Title { get; set; }
public IList<AttributeValue> AttributeValues { get; set; }
}
Your mapping would then look like this:
public class AttributeKeyMap : ClassMap<AttributeKey>
{
public AttributeKeyMap()
{
Id(x => x.Id, "ID");
Map(x => x.Title);
HasMany(x => x.AttributeValues)
.KeyColumn("AttributeKeyID")
.Inverse()
.Cascade.AllDeleteOrphan();
}
}

FluentNHibernate Unidirectional One-To-Many Mapping

I have two classes. One is Order:
public class Order
{
public virtual int Id { get; set; }
public virtual IList<Product> Products { get; set; }
}
The other one is Product:
public class Product
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
They are fluently mapped like this:
public class OrderMap : ClassMap<Order>
{
public OrderMap()
{
Table("Orders");
Id(x => x.Id, "Id");
HasMany(x => x.Products)
.KeyColumn("OrderId")
.Cascade.All();
}
}
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Table("Products");
Id(x => x.Id, "Id");
Map(x => x.Name);
}
}
The database does NOT have a not-null constraint on the OrderId column of the Products table.
Problem is: both the order and the products are being persisted, however the products are being persisted with a null value on the OrderId column.
Am I missing something?
instead of HasMany just use Reference
Reference(x => x.Products).Cascade.All();
Inverse on HasMany is an NHibernate term, and it means that the other end of the relationship is responsible for saving.
Well, as strange as it seems, we solved this issue here by re-working our Session management, using it to create an ITransaction in a using statement. Odd, but solved. Thanks everyone!
Try using:
HasMany(x => x.Products)
.KeyColumn("OrderId")
.Inverse()
.Cascade.All();
Which(Inverse()) states that OrderId is on the Products table