Fluent NHibernate Mapping for a Category / Sub-Categories Tree - fluent-nhibernate

I have the following model class for my 'Category' object:
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Category ParentCategory { get; set; }
public virtual IList<Category> SubCategories { get; set; }
This is my fluent nhibernate mapping class for 'Category':
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Name);
References(x => x.ParentCategory).Column("ParentCategoryId");
// ** THE BELOW MAPPING IS WHAT I'M UNSURE ABOUT **
HasMany(x => x.SubCategories).Where(x => x.Id == x.ParentCategory.Id);
My database that this relates to consists of a number of 'categories', some of which are at root level (and have a ParentCategoryId = NULL) and all others are sub-categories, which may be only 1 level deep, or may be 3,4,5 levels deep (recursive parents back up to a root/parent CategoryId.
Example of relationship between rows/records:
Cars (Id = 1 - ParentCategoryId = NULL)
Cars (Id = 1) > Hatchback (Id = 2 - ParentCategoryId = 1)
Cars (Id = 1) > Hatchback (Id = 2) > Ford (Id = 3 - ParentCategoryId = 2)
Motorcycles (Id = 4 - ParentCategoryId = NULL)
Motorcycles (Id = 4) > Scooters (Id = 5 - ParentCategoryId = 4)
The 'SubCategories' property within my Category class needs to retrieve all Categories that have a 'ParentCategoryId' of the current Category(Id), but I'm unsure how I go about mapping this. I've tried the HasMany mapping shown in the above example, but that failed.

I believe I have just implemented a working solution to this by changing the HasMany mapping to the following:
HasMany(x => x.SubCategories)
.Cascade.AllDeleteOrphan()
.KeyColumn("ParentCategoryId")
.Where(x => x.ParentCategory.Id == x.Id)

Related

Fluent NHibernate - Query using Criteria with filter on connecting table

I have following tables
User - Primary column - Id and other detail columns
Department - Primary column - Id and other detail columns
UserDepartment - Primary column - Id and other columns are UserId and DepartmentId
I want to find all users those are in department - (1 and 2).
I also want to find all users those are in department - (1 or 2).
Can anybody suggest me the criteria to get all users in department (1 and 2)? Another criteria to get all users in department - (1 or 2)?
I am new to FluentNHibernate, so didn't tried anything yet as I found nothing relevant on Google search? With the help of Google search, I was able to write criteria for 1-1 relations but not for above scenario.
assuming following classes
class User
{
public virtual int Id { get; private set; }
public virtual ICollection<Department> Departments { get; private set; }
}
class Department
{
public virtual int Id { get; private set; }
}
class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id);
HasManyToMany(x => x.Departments)
.Table("UserDepartment")
.ParentKeyColumn("UserId")
.ChildKeyColumn("DepartmentId");
}
}
then query for 1 or 2
var results = session.QueryOver<User>()
.JoinQueryOver<Department>(x => x.Departments)
.Where(d => d.Id.IsIn(departmentIds))
.List();
query for 1 and 2
User userAlias = null;
var subquery = session.QueryOver<Department>()
.Where(d => d.User.Id == userAlias.Id && d.Id.IsIn(departmentIds))
.Select(Projections.RowCount());
var results = session.QueryOver<User>()
.WithSubquery.WhereValue(departments.Count).Eq(subquery)
.List();

(Fluent) NHibernate: Map field from separate table into object

I'm currently trying to get (Fluent)NHibernate to map an object to our legacy database schema. There are three tables involved.
Table a contains most information of the actual object I need to retrieve
Table b is a table which connects table a with table c
Table c has one additional field I need for the object
An SQL query to retrieve the information looks like this:
SELECT z.ID, z.ZANR, e.TDTEXT
FROM PUB.table_a z
JOIN PUB.table_b t ON (t.TDKEY = 602)
JOIN PUB.table_c e ON (e.ID = t.ID AND e.TDNR = z.ZANR)
WHERE z.ZANR = 1;
The main problem is how to specify these two join conditions in the mapping.
Entity for table a looks like this:
public class EntityA
{
public virtual long Id { get; set; }
public virtual int Number { get; set; }
public virtual string Name { get; set; }
}
Name should map to the column table_c.TDTEXT.
The mapping I have so far is this:
public class EntityAMap : ClassMap<EntityA>
{
public EntityAMap()
{
Table("PUB.table_a");
Id(x => x.Id).Column("ID");
Map(x => x.Number).Column("ZANR");
}
}
I tried to map the first join with the same strategy as in How to join table in fluent nhibernate, however this will not work, because I do not have a direct reference from table_a to table_b, the only thing connecting them is the constant number 602 (see SQL-query above).
I didn't find a way to specify that constant in the mapping somehow.
you could map the name as readonly property easily
public EntityAMap()
{
Table("PUB.table_a");
Id(x => x.Id).Column("ID");
// if ZANR always has to be 1
Where("ZANR = 1");
Map(x => x.Number).Column("ZANR");
Map(x => x.Name).Formula("(SELECT c.TDTEXT FROM PUB.table_b b JOIN PUB.table_c c ON (c.ID = b.ID AND b.TDKEY = 602 AND c.TDNR = ZANR))");
}
Update: i could only imagine a hidden reference and the name property delegating to there
public EntityAMap()
{
HasOne(Reveal.Member<EntityA>("hiddenEntityC"));
}
public class EntityB
{
public virtual int Id { get; set; }
public virtual EntityA EntityA { get; set; }
}
public EntityCMap()
{
Where("Id = (SELECT b.Id FROM PUB.table_b b WHERE b.TDKEY = 602)");
References(x => x.EntityA).PropertyRef(x => x.Number);
}

NHibernate queryover with many-to-many

The situation is following:
1. Product belongs to many Categories,
2. Category has many Products.
class Product
{
public int Id { get; set; }
public List<Category> Categories { get; set; }
}
class Category
{
public int Id { get; set; }
public List<Product> Products { get; set; }
}
How to have all products, where each of them belongs to category with id = 2 and 3 and 4. How to do with queryover?
At the moment I use dynamically created hql:
select p from Product p where
exists (select c.id from p.Categories c where c.Id = 2)
and exists (select c.id from p.Categories c where c.Id = 3)
and exists (select c.id from p.Categories c where c.Id = 4)
And the mapping is:
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.Id);
HasManyToMany(x => x.Categories)
.Table("product_category")
.ParentKeyColumn("product_id")
.ChildKeyColumn("category_id");
}
}
public class CategoryMap : ClassMap<Category>
{
public CategoryMap()
{
Id(x => x.Id);
HasManyToMany(x => x.Products)
.Table("product_category")
.ParentKeyColumn("category_id")
.ChildKeyColumn("product_id");
}
}
Try this, maybe it's help:
Category categoryAlias = null;
session.QueryOver<Product>()
.JoinAlias(product => product.Categories, () => categoryAlias)
.WhereRestrictionOn(() => categoryAlias.Id).IsIn(new [] { 2, 3, 4 })
.List();

Not sure how to make a property on an object using Fluent NHibernate from custom query

I am trying to map the following structure:
public class Tag {
public Guid Id {get;set;}
public DateTime ActivatedDate {get;set;}
}
public class History {
public Guid Id {get;set;}
public TypeEnum Type {get;set;}
public Guid ContentID {get;set;}
public DateTime HistoryDate {get;set;}
}
Tag.ActivatedDate is actually populated by (select top 1 HistoryDate from History where ContentID = {tagid} && Type = 'Activated' order by HistoryDate desc
I'm really not sure how to Map this with Fluent NHibernate.
My mappings are:
public TagMapping() {
Table("Tags");
Id(x => x.Id)
}
public HistoryMapping() {
Table("History");
Id(x => x.Id);
Map(x => x.Type).CustomeType<TypeEnum>();
Map(x => x.ContentID);
Map(x => x.HistoryDate);
}
I'm not sure how to map Tag.ActivatedTop
Basically looking for:
SELECT tag.Id,
(select top 1 HistoryDate from History
where ContentID = tag.Id
AND Status = 'Activated'
order by HistoryDate desc) As ActivatedDate
FROM Tags tag
Ended up doing:
Map(x => x.ActivatedDate)
.ReadOnly()
.Formula(
string.Format(
"(select top 1 h.HistoryDate from History h where h.ContentID = Id AND h.Status = 'Activated' order by h.HistoryDate desc)"));

map table to itself in Parent-Child relationship Fluent Nhibernate

I have situation where I am mapping table's columns to the primary key of same table. The table looks like this
---+-------+---------
ID Name ParentId
---+-------+---------
1 Parent1 0
2 Child 1 1
3 Child 2 1
4 Parent2 0
5 Child 3 4
I have created a following Model and Fluent NHibernate mapping class
//Model.LocationType.cs
public class LocationType
{
public virtual long Id { get; set; }
public virtual string ShortName { get; set; }
public virtual string Description { get; set; }
public virtual IList<LocationType> ParentId { get; set; }
}
and
//Mapping.LocationTypeMap.cs
public class LocationTypeMap : ClassMap<LocationType>
{
public LocationTypeMap()
{
Table("SET_LOC_TYPE");
Id(x => x.Id).Column("LOC_TYPE_ID").GeneratedBy.Assigned();
Map(x => x.ShortName, "SHORT_NAME").Length(15).Not.Nullable();
Map(x => x.Description, "LOC_DESC").Length(50).Not.Nullable();
References(x => x.ParentId).Column("PARENT_LOC_TYPE_ID").Cascade.SaveUpdate();
}
}
but I am receiving follow error message when i execute my code:
Unable to cast object of type 'SmartHRMS.Core.Domain.Model.LocationType' to type 'System.Collections.Generic.IList`1[SmartHRMS.Core.Domain.Model.LocationType]'.
Edit 1:
Instead of using i tried
HasMany(x => x.ParentIds).KeyColumn("PARENT_LOC_TYPE_ID");
Although it worked and solved the casting problem that I mentioned above but the result I am gettting is the reverse of what i need.
In parent's LocationType objects, it lists all childs in IList, so for above example the result will be:
-----+----------+------
ID Name ParentId
-----+----------+------
1 Parent1 IList<Child1, Child2>
2 Child 2 IList<Empty>
3 .... same
4 Parent2 IList<Child3>
5 Child 3 IList<Empty>
Seems like you should use HasMany in your mapping instead of References.