nhibernate: project a Parent from a child-query - nhibernate

I have the following entities
public class ArticleCategory
{
public int Id {get; set;}
public string Name {get; set;}
public IList<Article> Articles {get; set;}
}
public class Article
{
public int Id {get; set;}
public string Name {get; set;}
public ArticleCategory Category {get; set;}
}
public class JobArticles
{
public int Id {get; set;}
public Job Job {get; set;}
public decimal Price {get; set;}
public Article Article {get; set;}
}
As you can see Article knows nothing about to which JobArticle it has been assigned (it's not relevant)
So what I need to do is the following.
Get every ArticleCategory for which there exist JobArticles for Job X.
The easiest way would be to Add the List of JobArticles to the Article Entity. But I'm not sure if it is the best way.
So I tried the opposite way (going from JobArticle to ArticleCategory). Something like that
IQueryOver<JobArticle, JobArticle> q = DataSession.Current.QueryOver<JobArticle>();
Article ArticleAlias = null;
ArticleCategory ArticleCategoryAlias = null;
q.JoinAlias(x => x.Article, () => ArticleAlias);
q.JoinAlias(x => ArticleAlias.Category, () => ArticleCategoryAlias);
q.Where(x => x.Job.Id == jobId);
q.SelectList(list => list
.Select(x => ArticleCategoryAlias))
Which leads to a NULL-Reference Exception because .Select(x => ArticleCategoryAlias)
I'm not really sure how to do it, hope you can help

Article ArticleAlias = null;
ArticleCategory ArticleCategoryAlias = null;
var categories = DataSession.Current.QueryOver<ArticleCategory>()
.WithSubquery.WhereProperty(x => x.Id).In(QueryOver.Of<JobArticle>()
.JoinAlias(x => x.Article, () => ArticleAlias);
.JoinAlias(x => ArticleAlias.Category, () => ArticleCategoryAlias);
.Where(x => x.Job.Id == jobId);
.Select(() => ArticleCategoryAlias.Id))
.List();

Related

Database structure with Entity Framework Core - Discrimination

I have the following problem:
I'd like to be able sell a few kinds of products in my store.
I have created following infrastructure:
public class Product
{
public int Id {get; set;}
public string Name {get; set;}
...
public int? ParentId {get; set;}
public Product Parent {get; set;}
public ICollection<Product> Children {get; set;}
}
public class AudioFile : Product
{
public string SomeValue {get; set;}
}
public class DocummentFile : Product
{
public string SomeString {get; set;}
}
In fluent mapping I am using discriminator.
So, to Select the amount of documment files without a parent, I am doing something like this:
DbContext.DocummentFiles.Count(x=> !x.ParentId.HasValue)
It works with Audio files too.
I'd like to select sample dictionary of all children for some audio file with SomeValue:
DbContext.AudioFiles
.Where(x => x.ParentId == 222)
.Select(x => x.Children
.OfType<AudioFile>()
.ToDictionary(t => t.Name, t => t.SomeValue));
Unfortunately, it does not work. I have high CPU usage by the long time, but I have not any result.

Fluent NHibernate Mapping and Retrieve Hierarchy Table

I have a hierarchy category table like this
Id int,
Description varchar(100),
ParentId int,
Ordinal int,
IsActive bit
I want to fetch all of the Categories from parent to child, so when I called session.get<Category>(id), it already fetched all of their children. Here is my map and class:
class Category
{
public virtual int Id {get; set;}
public virtual string Description {get; set;}
public virtual int ParentId {get; set;}
public virtual int Ordinal {get; set;}
public virtual bool IsActive {get; set;}
}
class CategoryMap : ClassMap<Category>
{
public CategoryMap()
{
Table("TB_CATEGORY");
Id(f => f.Id).GeneratedBy.Native();
Map(f => f.Description);
Map(f => f.ParentId);
Map(f => f.Ordinal);
Map(f => f.IsActive);
}
}
I've searched so many articles, and am still confused when using their solutions because they don't tell me about the table structure and the mappings. Like this one from ayende blog, I think its a good solution, but I can't follow it well enough to apply this in my project.
Could somebody give me a step by step tutorial to achieve this? Are my mapping and class correct?
using the following classes
class Category
{
public virtual int Id {get; private set;}
public virtual string Description {get; set;}
public virtual Category Parent {get; set;}
public virtual bool IsActive {get; set;}
public virtual IList<Category> Children {get; private set;}
public override bool Euqals(object obj)
{
var other = obj as Category;
return other != null && (Id == 0) ? ReferenceEquals(other, this) : other.Id == Id;
}
public override int GetHashCode()
{
return Id;
}
}
class CategoryMap : ClassMap<Category>
{
public CategoryMap()
{
Table("TB_CATEGORY");
Id(f => f.Id).GeneratedBy.Native();
Map(f => f.Description);
References(f => f.Parent).Column("ParentId");
HasMany(f => f.Children)
.AsList(i => i.Column("Ordinal")) // let the list have the correct order of child items
.KeyColumn("ParentId")
.Inverse(); // let the reference maintain the association
Map(f => f.IsActive);
}
}
then you can query
var categoriesWithChildrenInitialised = session.QueryOver<Category>()
.Fetch(c => c.Children).Eager
.List()

Fluent nhibernate map list of items

I have a class "Company" which has a list of "Operator"
public class Company
{
public IList<Opertator> Operators {get; set; }
public Int32 Id {get; set;}
}
public class Operator {
public Int32 Id {get; set; }
public Company Company {get; set; }
}
When I mapped as follows:
public class CompanyMapping : ClassMap<Company>
{
public ProductMapping() : base()
{
Id(x => x.Id, "CompanyId").GeneratedBy.Native();
HasMany(x => x.Operators);
}
}
public class OperatorMapping : ClassMap<Operator>
{
public OperatorMapping()
{
Id(x => x.Id);
Reference(x => x.Company);
}
}
I have a UI where user can add operators and remove operators by checking boxes.
in c# code, I query the stored company, and add to the list, or remove from the list.
then send SaveOrUpdate.
My problem is when I add one more operator to existing company, and save/Update, the NHibernate is deleting the whole list, and reinster them again.
I don't want to do that.
Can I have it, that NHibernate will detect the changed items (new items from the list, and insert them, and determine the deleted item and delete them)?
I tried change the mapping to have in the company mapping
HasMany(x => x.Operators).Inverse();
but it end up not deleting at all.
Any help?
Inverse says that the Operator is responsible for the association and you have to set it when adding an Operator to the Company
public class Company
{
public Int32 Id {get; set;}
public ICollection<Opertator> Operators {get; private set; }
public void Add(Opertator operator)
{
Operators.Add(operator);
operator.Company = this;
}
public Company()
{
Operators = new List<Operator>();
}
}
// and
HasMany(x => x.Operators).Inverse();
// use it like
company.Add(new Operator()); // instead of company.Operators.Add(new Operator());

Fluent NHibernate mapping a class where the Id is a reference to another class

I am trying to use fluent nHibernate to map a class that only exists as a container for other classes, and doesn't have an Id of its own. But I want the Id of the class to be a different class. That really doesn't make sense, it might be easier to explain with an example data structure.
abstract QueryBuilder
{
public IEnumerable<string> Category1Keys {get; set;}
public IEnumerable<int> Category2Ids {get; set;}
public IEnumerable<int> Category3Ids {get; set;}
}
Set
{
public int Id {get; set;}
public string Name {get; set;}
public SetQueryBuilder QueryBuilder{get; set;}
}
SetQueryBuilder : QueryBuilder
{
}
News
{
public int Id {get; set;}
public string Name {get; set;}
public NewsQueryBuilder QueryBuilder{get; set;}
}
NewsQueryBuilder : QueryBuilder
{
}
Now the QueryBuilder is the name is a concept that we use to map various (unrelated) items to the same categories. So things that might use QueryBuidler are News, Pages, Permissions.
Becuase all the various items that use QueryBuilder map that relationship in the same way, and ocasionally we actually use the paramters from one type of QueryBuilder as a the select criteriea for another type of QueryBuilder (ie if news has QB of A, get all the Sets that match the same criteria), I want to have a abstract QueryBuilder class, and then extend it for all the things that have mappings to all the categories.
Here is an example of the Set DB for query builder. There isn't an actual item in the DB for QueryBuilder - its composed of all the info from the category class join tables.
f_set
{
set_id (PK, int)
name (varchar)
}
f_set_cat1
{
set_id (PK, FK, int)
cat1_key (PK, FK, char(3))
}
f_set_cat2
{
set_id (PK, FK, int)
cat2_id (PK, FK, int)
}
f_set_cat3
{
set_id (PK, FK, int)
cat3_id (PK, FK, int)
}
My problem is how to map each instance of the QueryBuilder class in nHibernate, as it doesnt' have a real key or table entry, I would like to say that the Id is a reference to the Set that all the category mappings use.
Here are my fluent mappings so far:
SetMapping : ClassMap<Set>
{
public SetMapping()
{
Schema("cam");
Table("f_set");
Id(x => x.Id, "f_set_id").GeneratedBy.Identity();
Map(x => x.Name, "name").Not.Nullable();
HasOne<SetQueryBuilder>(x => x.QueryBuilder);
}
}
SetQueryBuilderMapping : ClassMap<SetQueryBuilder>
{
public SetQueryBuilderMapping()
{
References(x => x.Set, "set_id");
HasMany(x => x.Category1Keys).Table("f_set_cat1").Element("cat1_key").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat2").Element("cat2_id").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat3").Element("cat3_id").KeyColumn("set_id");
}
}
Any help with the final step of the mapping would be hugely appreciated
Thanks
Saan
FURTHER INVESTIGATION
Ok I have done a bit mroe investigating on this and have foudn that combining the two classes works fine if I do this:
CLASS:
Set
{
public int Id {get; set;}
public string Name {get; set;}
//public SetQueryBuilder QueryBuilder{get; set;}
public IEnumerable<string> Category1Keys {get; set;}
public IEnumerable<int> Category2Ids {get; set;}
public IEnumerable<int> Category3Ids {get; set;}
}
MAPPING
SetMapping : ClassMap<Set>
{
public SetMapping()
{
Schema("cam");
Table("f_set");
Id(x => x.Id, "f_set_id").GeneratedBy.Identity();
Map(x => x.Name, "name").Not.Nullable();
//HasOne<SetQueryBuilder>(x => x.QueryBuilder);
HasMany(x => x.Category1Keys).Table("f_set_cat1").Element("cat1_key").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat2").Element("cat2_id").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat3").Element("cat3_id").KeyColumn("set_id");
}
}
When doing nHibernate mappings this makes perfect sense, but I would really like to have all the category mappings in the separate SetQueryBuilder class.
Thanks again for any help
Saan
You are looking for subclassing strategy. Take a look at this http://nhibernate.info/doc/nh/en/index.html#inheritance
You probably want to follow a table per class with table per subclass strategy imo.

get property count with entity using nhibernate

can I am hoping someone can point me to the right direction on how to get count of a property and the entity using a single trip to sql.
public class Category
{
public virtual int Id { get; private set; }
public virtual string Description { get; set; }
public virtual IList<Article> Articles { get; set; }
public virtual int ArticlesCount { get; set; }
public Category()
{
Articles=new List<Article>();
}
public virtual void AddArticle(Article article)
{
article.Category = this;
Articles.Add(article);
}
public virtual void RemoveArticle(Article article)
{
Articles.Remove(article);
}
}
public class CategoryMap:ClassMap<Category>
{
public CategoryMap()
{
Table("Categories");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Description);
HasMany(x => x.Articles).KeyColumn("CategoryId").Fetch.Join();
Cache.ReadWrite();
}
}
My goal is to get the all Categories and the count of the associated articles if there is any.
I have tried this
ICriteria crit = session.CreateCriteria(typeof(Category));
crit.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("Description"), "Description")
.Add(Projections.Count("Articles"), "ArticlesCount"));
crit.SetResultTransformer(Transformers.AliasToBean (typeof(Category)));
var aa=crit.List();
unfortunately the generated sql shows the count of the Category table not the Articles list.
Thanks
You could use a multi-query, multiple sql statements but it is one trip to the database.
Here is an example from the nhibernate documentation:
https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/performance.html
IMultiQuery multiQuery = s.CreateMultiQuery()
.Add(s.CreateQuery("from Item i where i.Id > ?")
.SetInt32(0, 50).SetFirstResult(10))
.Add(s.CreateQuery("select count(*) from Item i where i.Id > ?")
.SetInt32(0, 50));
IList results = multiQuery.List();
IList items = (IList)results[0];
long count = (long)((IList)results[1])[0];
Maybe not exactly what you were thinking.