FluentNHibernate Many-To-Many Conditional Count on Child - fluent-nhibernate

Consider the following entities:
Package Manifest Content
---------- ---------- ----------
Id PackageId Id
Name ContentId Name
Status
The relationship is many-to-many where a package can have multiple contents and contents can belong to multiple packages.
What I'd like to do is, for a given Package.Id, get the count of all Content which have a specific Status.
My mapping works fine, but I have not been able to figure out how to achieve a conditional count of the Content without loading the Content. One option is to use an ApplyChildFilter in the mapping and use with ExtraLazyLoad, but this means I'd have to create a dedicated property just for this.
Is there a way to achieve this without falling back on CreateSQLQuery?

Does the following query work for you?
session
.QueryOver<Package>()
.JoinQueryOver(x => x.Manifest)
.JoinQueryOver(x => x.Content)
.Where(x => x.Status == someStatus)
.Select(Projections.RowCount())
.FutureValue<int>()
.Value

Related

can't get relation's name via listdata

I am not sure why I can't get the columns from my other tables via my relations. I was thinking is it because of my scope? After i had a default scope in my models, everything seems to be out of place, even if i use resetscope() at some places. Some sections I can't get to my relation columns; when that happens, I'd have to use Model::model->findbypk(n)->name.. that doesn't look pretty.
the id shows if i don't have the relations, but the name is blank when i put the relation name.
CHtml::listData(Model::model()->findAll(),'product_id','main.product_name'),
my model defaultscope is pretty basic:
return array(
'condition'=>'store_id1=:store_id OR store_id2=:store_id' ,
'params' => array(':store_id' => $store_id)
);
You can change the way you use your model like below:
Model::model()->with('main')->findAll();

(NHibernate) how to filter a collection on fetch

Requirement:
I'm trying to query a list of customers.
Each customer can contain a list of contacts.
Only active contacts should be returned.
Code:
Session.QueryOver<Customer>()
.Fetch(x => x.Contacts.Where(c => c.Active))
.Eager
.TransformUsing(new DistinctRootEntityResultTransformer())
.Future()
.AsQueryable();
Error:
Unrecognised method call in expression x.Contacts.Where(c => c.Active)
So, how can I filter only active contacts?
You don't because doing so would create a mismatch between the database and the domain model. If you were able to do this, the inactive contacts would be deleted when the session is flushed. There are two good options:
Create an extension method on IEnumerable<Contact> that returns active contacts. This allows you to easily filter any set of Contacts to display only the active ones.
Create a view model containing only the data you want to display.
NHibernate filters may also be an option but I have no experience with them. I favor using extension methods.

NHibernate Queryover - How do I return only a child collection

I am running into difficulty with the following nhibernate queryover query. I am probably over-complicating things, but here is the problem:
I have an entity named AuctionStatistic that links to an auction (this is uni-directional and I do not have links from auctions back to statistics)
I would like to query the statistic table, find all auction IDs and pull back only those that meet a certain threshold - i.e. top 500 auctions by views
Once I've gotten the top X (in this example i'm hardcoding to 10000 views) I want to pull back the auction id and name. For this particular query I don't need any of the data stored in the statistics table (though this is used elsewhere and is not redundant)
I figured I could use something like the following to get back just the auctions, but because I'm querying over AuctionStatistic it expects the selected value to be of type AuctionStatistic (or a list thereof)
var auctions = _session.QueryOver<AuctionStatistic>().Where(c => c.ViewCount > 10000).Fetch(x=>x.Auction).Eager.Select(x=>x.Auction);
Can anyone suggest a better way of doing this?
Thanks
JP
Without bi-directional this is probably your best bet.
Auction auctionAlias = null;
AuctionDTO dto = null;
var auctionDtos = _session.QueryOver<AuctionStatistic>()
.Where(c => c.ViewCount > 10000)
.JoinAlias(x => x.Auction, () => auctionAlias)
.SelectList(list => list
.Select(() => auctionAlias.id).WithAlias(() => dto.id)
.Select(() => auctionAlias.name).WithAlias(() => dto.name))
.TransformUsing(Transformers.AliasToBean<AuctionDTO>())
.List<AuctionDTO>();

Fluent nHibernate Selective loading for collections

I was just wondering whether when loading an entity which contains a collection e.g. a Post which may contain 0 -> n Comments if you can define how many comments to return.
At the moment I have this:
public IList<Post> GetNPostsWithNCommentsAndCreator(int numOfPosts, int numOfComments)
{
var posts = Session.Query<Post>().OrderByDescending(x => x.CreationDateTime)
.Take(numOfPosts)
.Fetch(z => z.Comments)
.Fetch(z => z.Creator).ToList();
ReleaseCurrentSession();
return posts;
}
Is there a way of adding a Skip and Take to Comments to allow a kind of paging functionality on the collection so you don't end up loading lots of things you don't need.
I'm aware of lazy loading but I don't really want to use it, I'm using the MVC pattern and want my object to return from the repositories loaded so I can then cache them. I don't really want my views causing select statements.
Is the only real way around this is to not perform a fetch on comments but to perform a separate Select on Comments to Order By Created Date Time and then Select the top 5 for example and then place the returned result into the Post object?
Any thoughts / links on this would be appreciated.
Thanks,
Jon
A fetch simple does a left-outer join on the associated table so that it can hydrate the collection entities with data. What you are looking to do will require a separate query on the specific entities. From there you can use any number of constructs to limit your result set (skip/take, setmaxresults, etc)

EF: How to do effective lazy-loading (not 1+N selects)?

Starting with a List of entities and needing all dependent entities through an association, is there a way to use the corresponding navigation-propertiy to load all child-entities with one db-round-trip? Ie. generate a single WHERE fkId IN (...) statement via navigation property?
More details
I've found these ways to load the children:
Keep the set of parent-entities as IQueriable<T>
Not good since the db will have to find the main set every time and join to get the requested data.
Put the parent-objects into an array or list, then get related data through navigation properties.
var children = parentArray.Select(p => p.Children).Distinct()
This is slow since it will generate a select for every main-entity.
Creates duplicate objects since each set of children is created independetly.
Put the foreign keys from the main entities into an array then filter the entire dependent-ObjectSet
var foreignKeyIds = parentArray.Select(p => p.Id).ToArray();
var children = Children.Where(d => foreignKeyIds.Contains(d.Id))
Linq then generates the desired "WHERE foreignKeyId IN (...)"-clause.
This is fast but only possible for 1:*-relations since linking-tables are mapped away.
Removes the readablity advantage of EF by using Ids after all
The navigation-properties of type EntityCollection<T> are not populated
Eager loading though the .Include()-methods, included for completeness (asking for lazy-loading)
Alledgedly joins everything included together and returns one giant flat result.
Have to decide up front which data to use
It there some way to get the simplicity of 2 with the performance of 3?
You could attach the parent object to your context and get the children when needed.
foreach (T parent in parents) {
_context.Attach(parent);
}
var children = parents.Select(p => p.Children);
Edit: for attaching multiple, just iterate.
I think finding a good answer is not possible or at least not worth the trouble. Instead a micro ORM like Dapper give the big benefit of removing the need to map between sql-columns and object-properties and does it without the need to create a model first. Also one simply writes the desired sql instead of understanding what linq to write to have it generated. IQueryable<T> will be missed though.