NHibernate - Filtered ManyToMany relationship returns null records - nhibernate

I have two entities (Job and Location) that are connected through a many-to-many relationship.
Recently we implemented soft delete logic on the Location entity and then added a filter on the job Mapping like this:
HasManyToMany(x => x.Locations)
.Table("JobLocation")
.ParentKeyColumn("JobId")
.ChildKeyColumn("LocationId")
.ApplyChildFilter<ExcludeDeletedFilter>("IsDeleted = :condition")
.Cascade.None();
The query for the many-to-many relationship looks like this
select ...
from Job job
left outer join JobLocation jl
on jl.JobId = job.Id
left outer join Location loc
on loc.Id = jl.LocationId and IsDeleted = 0
The problem is that now, when fetching a Job that has some deleted locations, the Locations collection on the job entity contains a null entry for each deleted Location.
What is the best way to handle this soft delete records when they are fetched through a many-to-many relationship. (for one to many, this filter does a great job)
What other alternatives should I consider to do this?

Items in a list are associated with an index. When persisted using a list-style mapping, these indices will be preserved (lists normally don't suddenly rearrange themselves).
If you filter some items, to make the visible items have stable positions, it follows that there must be null items for the hidden elements.
Consider using a different mapping, such as a set, bag or map.

Related

How to join Two tables of two non relashinship defined columns using Nhibernate QueryOver

Using NHibernate QueryOver, I want to join two tables using two columns which are not defined in the mapping as a relationship.
E.g. This is not my exact scenario but this can explain that
Tables:
Employee(Id, Name, DepartmentId, SomeCode,Address)
Department (Id, Name, ,Code)
Select
SELECT *
FROM EMPLOYEE E
JOIN DEPARTMENT D
ON D.Code = E.SomeCode
Can someone please tell me how to do this query using NHibernate QueryOver. Note that "SomeCode" in Employee and "Code" in Department are not defined as a relationship. DepartmentId is the foreign key and I can join these using JoinAlias but I want it in a somewhat different way.
There are similar questions, e.g.
NHibernate (+ FluentNhibernate) : Join two detached tables
Hibernate Criteria Projection without mapped association of tables
And the answer is:
either use HQL and CROSS JOIN (with WHERE)
There is NO way how to do that with QueryOver/Criteria)
See the doc:
14.2. The from clause
Multiple classes may appear, resulting in a cartesian product or "cross" join.
from Formula, Parameter
from Formula as form, Parameter as param
So using HQL in your case, we can do it like this:
SELECT ...
FROM EMPLOYEE E, DEPARTMENT D
WHERE D.Code = E.SomeCode
...
BUT I would suggest: create that mapping in the code. Simply introduce many-to-one relation. It will be loaded lazily (only if used) and will nicely serve to our needs - be used in QueryOver as a relation for Join
If there is such relation, if this exist in the business object domain, we should not be scared to use it. We can hide it via security etc...

Fluent NHibernate One-to-Many Mapping Results in Bad Query

I have a pretty simple one to many mapping using Fluent NHibernate and it works fine except the the queries NH generates are less than ideal. I found this when I checked the sql log from NH.
The query I am looking for is like
select p.*, c.* from parent p inner join child c on p.Id = c.parentId
where p.ID is the PK of the parent table and c.ParentId is a FK in the child table pointing to the PK of the parent table.
But what I found from the sql log is something like this:
select P.* from Parent
followed by a bunch of queries running against the child table like
select * from child c where c.ParentId = #p0
Not surprisingly this is causing performance issues.
My question is why NH is not generate the inner join query I think it should? What do I need to change so that NH will generate the desired query?
The JOIN is not suitable in this scenario. It will produce SELECT resulting in more rows, then the Parent table has. I.e: each child of a parent will append new row.
The appropriate solution here is to keep these selects separated. Firstly select the parent, then load all children for all parents (just selected parents). NHibernate does have nice solution for this:
19.1.5. Using batch fetching
Fluent version described here: How to Eager Load Associations without duplication in NHibernate?
This would work a bit similar as you experienced. Firstly select parent, then go for child(ren). The biggest difference is, that instead of 1 + N (going for each children collection separately) we now go for more children in batches. so it could be 1 + 2
Examples of the batch size mapping
1) Colleciton
HasMany<Child>(x => x.Children)
.BatchSize(25);
2) Entity itself
public ChildMap()
{
Id(x => x....
...
BatchSize(25);
There are many other advantages, where the PAGING is one of the most profitable. Because we are working with a flat (not multiplied) Parent, we can apply .Take() and .Skip()
Finally, fi we would like to find some Parents based on their children, we can use in this scenario Subqueries: 15.8. Detached queries and subqueries

Handeling many-to-many as multiple one-to-one when read

Is there a way to handle a one-to-many relationship as if they would be multiple one-to-one entries?
For all users I have to display all the tasks that are assigned to them in a list, sorted by user, but when a task is assigned to multiple users I have to display it multiple times in the list.
IF I understand it well, you have User (0,n) ----- (0,n) Task
So you should have in the physical implementation :
User(0,n) ----- (1,n)User_to_Task(1,n) ----- (0,n)Task
Then you just have to select from the User_to_Task table to have like a multiple one-to-one relationship:
SELECT * FROM User_to_Task
JOIN User ON USE_Id = UTT_USE_Id
JOIN Task ON TAS_Id = UTT_TAS_Id
ORDER BY USE_Id

Limiting NHibernate Entities Returned

I'm trying to limit the number of entities that an NHibernate Criteria will return. The standard seems to be to use SetMaxResults, but this doesn't work properly if my Criteria involves a LEFT OUTER JOIN on a many-to-many relationship.
An example:
Dogs have owners (a many-to-many relationship), and I need to retrieve up to 10 dogs that belong to some set of owners. Doing
session.CreateCriteria<Dog>()
.CreateAlias("Owners", "Owners")
.Add(Restrictions.In("Owners.Id", idCollection)
.SetMaxResults(10)
.List<Dog>();
will translate into a SQL query like
SELECT TOP(10) * FROM DOGS d
LEFT OUTER JOIN OWNERS_DOGS od ON d.id = od.id
WHERE od.OWNER_ID IN (:valueone, :valuetwo)
My TOP restriction is happening too early, causing a dog with multiple owners that match the criteria to count multiple times towards my limit of 10. Is there a clean way to tell NHibernate that I only want it to hydrate the first X dog objects? I probably won't be able to get out of performing a full SELECT on the database, but it would be nice if I could avoid loading up every dog in the system, since I'm only going to be displaying 10 of them.
Solution in this case is a subquery. What we need is to create the inner SELECT, which will be filtered by dog owners and return the Dog ID. Then we will query Dogs, filter them by that subquery. Finally, our paging will be correct, while executed over the flat structure.
See this answer with more details: https://stackoverflow.com/a/14080092/1679310
Subquery 15.8. Detached queries and subqueries:
DetachedCriteria subQuery = DetachedCriteria.For(typeof(Dog))
// WHERE conditions go here
.SetProjection( Projections.Property("ID") )
;
The query with correct paging
session.CreateCriteria(typeof(Dog))
.Add(Subqueries.PropertyEq("ID", subQuery));
// PAGING goes here
.SetMaxResults(10)
.List();

Efficiently getting a count of child records when returning parent record(s)

I am using Entity Framework 4.1 using the Code First approach. I have two entities that exhibit a parent-child relationship. To provide a concrete example, imagine I have a Category entity that has zero-to-many Product entities associated with it. I have set up navigation properties on both sides (in my example, the Category entity would have an ICollection<Product> property while the Product entity has a Category property).
Now, when I get Category entities I want to also get back a count of the number of children records for each category. I am aware I can do:
Category category = dbContext.Categories.Single(...);
int productCount = category.Products.Count();
But I am concerned because the resulting SQL that gets sent to the database depends on whether I use lazy or eager loading.
In the first case (lazy loading), the call to the Products collection prompts EF to run a SQL query like:
SELECT ... all columns ...
FROM Products
WHERE CategoryID = #CategoryID
In the second case (eager loading), the products are loaded when the category information is retrieved so there is no second query to the database, but the downside is that if I'm not at all interested in products (other than their count) then I'm bringing back a lot of unneeded data.
What I'd like it to have the best of both worlds: namely, the ability to have just one database query and one that uses SELECT COUNT(*) rather than one that gets all of the columns from the table. In short, I'd like SQL like the following to be sent to the database:
SELECT ... all category columns ...,
(SELECT COUNT(*) FROM Products p WHERE p.CategoryID = c.CategoryID)
FROM Categories c
WHERE c.CategoryID = ...
Is that at all possible with EF or is what I want a pipe dream?
Not sure, but maybe try this:
var result = db.Categories.Where(x => x.CategoryId == categoryId)
.Select(y => new
{
Count = y.Products.Count(),
Category = y
})
.Single();
//result.Count
//result.Category
Yes, this is possible with EF. You can also create a view model to show the information with the child counts as properties. This article cover how to do that.
http://www.ozkary.com/2015/04/entity-framework-associated-table.html