NHIbernate Linq group by count - linq

I have the version 3.0.0.1001 nhibernate.
My objects are basically modeiling a lineup at an event. So I have a StageSet object which represents one slot in the schedule for a stage.
Each StageSet object has a Stage and an Act property.
It also has many Users - people who have favorited the set.
I'm trying to ascertain the most popular sets that have been favorited using the following linq:
var topStars = from s in Db.StageSets
group s by s.Act.Id into g
select new { SetKey = g.Key, Count = g.Count() };
However this just fails with a Could not execute query[SQL: SQL not available] error
Should I be able to do this?
w://

in case someone comes here. The following should work with NH 3.1
var topStars = from s in Db.StageSets
group s by s.Act.Id into g
select new { SetKey = g.First().Act.Id, Count = g.Count() }

You've specified the query correctly in linq. NHibernate is refusing to translate it.

I just copied your query with a slightly different domain and it worked. But that will count StageSets by Act, NOT favorites.

Related

How to write SQL translateable linq code that groups by one property and returns distinct list

I want to change code below to be sql translateable because now i get exception.
Basicallly i want list of customers from certain localisation and there could be more than one customer with the same CustomerNumber so i want to take the one that was most recently added.
In other words - distinct list of customers from localisation where "distinct algorithm" works by taking the most recently added customer if there is conflict.
The code below works only if it is client side. I could move Group By and Select after ToListAsync but i want to avoid taking unnecessary data from database (there is include which includes list that is pretty big for every customer).
var someData = await DbContext.Set<Customer>()
.Where(o => o.Metadata.Localisation == localisation)
.Include(nameof(Customer.SomeLongList))
.GroupBy(x => x.CustomerNumber)
.Select(gr => gr.OrderByDescending(x => x.Metadata.DateAdded).FirstOrDefault())
.ToListAsync();
Short answer:
No way. GroupBy has limitation: after grouping only Key and Aggregation result can be selected. And you are trying to select SomeLongList and full entity Customer.
Best answer:
It can be done by the SQL and ROW_NUMBER Window function but without SomeLongList
Workaround:
It is because it is not effective
var groupingQuery =
from c in DbContext.Set<Customer>()
group c by new { c.CustomerNumber } into g
select new
{
g.Key.CustomerNumber,
DateAdded = g.Max(x => x.DateAdded)
};
var query =
from c in DbContext.Set<Customer>().Include(x => x.SomeLongList)
join g in groupingQuery on new { c.CustomerNumber, c.DateAdded } equals
new { g.CustomerNumber, g.DateAdded }
select c;
var result = await query.ToListAsync();

Dynamic Linq core

Hi I am using a Jqwidgets Grid to display my data. It has a build in possibility to use filters but if you filter your records on the server side you have to build your own query. As I am working with Linq I thought to use the Dynamic Linq Library for Asp net core. Problem is there are not many examples or explanations how to do this. But I am busy for days now and not getting very far.The way I am setup; I have a normal Linq query:
var Mut = from M in _DB.Mutations
join S in _DB.Shifts on M.ShiftId equals S.ShiftId
join U in _DB.RoosterUsers on M.UserId equals U.RoosterUserId
join D in deps on M.UserId equals D.UserId
join DD in _DB.Departements on D.DepartementID equals DD.DepartementId
select new MutationModel
{
MutId=M.MutationId,
Naam=U.FirstName + " " + U.LastName,
UserId=M.UserId,
Departement= DD.DepartementName,
MutationType = S.publicName,
MutationGroup = S.ShiftType.ToString(),
DateTot =M.DateTill,
TijdVan=M.DateStartOn,
TijdTot=M.DateTill,
Status=CreateStatus(M.Tentative, M.ApprovedOn, M.Processed, M.CancelRefId, M.Deleted)
};
This query is running OK and gives me all the data I need for the Grid.
Then for the filter I would like to add a dynamic Linq Query using the System.Linq.Dynamic.Core library
But this is as far as I get things working until now:
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").Select("Status");
My questions now :
1. In the where clause If I make the fieldname variable I get an error. how to do this??
2. In the Select Clause, how to add multiple Columns? (actually I just like to output all columns.)
Best would be to see an example. has somebody used Dynamic Linq to build a dynamic linq query for the JQWidgets Grid?
Thank you very much.
In what way you are trying to use fieldname variable in where clause ?
If you want to output all columns you can use ToList()
like
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").ToList();
If you want to get some specific columns you can use Select clause like this
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").Select("new(Status,UserId )");
This Select clause creates data class which contains Status and UserId properties and returns a sequence of instances of that data class.

Wait for DomainContext.Load<t> from an entityquery with joins to complete (returning new type via 'select new')

My app consolidates data from other DBs for reporting purposes. We can't link the databases, so all the data processing has to be done in code - this is fine as we want to allow manual validation during the imports.
Certain users will be able to start an update through the Silverlight 4 front end.
I have 3 tables in database x that are fed from one EF4 Model (ModelX). I want to join those tables together, select specific columns and return the result as a new entity that exists in a different EF4 Model (ModelY). I'm using this query:
var myQuery = from i in DBx.table1 from it in DBx.table2 from h in DBx.table3 where (i.id==it.id && h.otherid == i.otherid) select new ModelYServer {Name = i.name,Thing = it.thing, Stuff = h.stuff};
The bit i'm stuck on, is how to execute that query, and wait until the Asynchronous call has completed. Normally, i'd use:
DomainContext.Load<T>(myQuery).Completed += (sender,args) =>
{List<T> myList = ((LoadOperation<T>)sender.Entities.ToList();};
but I can't pass myQuery (an IEnumerable) into the DomainContext.Load() as that expects an EntityQuery. The dataset is very large, and is taking up to 30 seconds to return, so I definitely need to wait before continuing.
So can anyone tell me how I can wait for the IEnumerable query to complete, or suggest a better way of doing this (there very likely is one).
Thanks
Mick
One simple way is just to force it to evaluate by calling ToList:
var query = from i in DBx.table1
join it in DBx.table2 on i.id equals it.id
join h in DBx.table3 on i.otherid equals h.otherid
select new ModelYServer {
Name = i.name,
Thing = it.thing,
Stuff = h.stuff
};
// This will block until the results have been fetched
var results = query.ToList();
// Now use results...
(I've changed your where clause into joins on the earlier tables, as that's what you were effectively doing and this is more idiomatic, IMO.)

How do I retrieve only certain subobjects in LINQ?

I have an entity object (Company) which has 1 or more subobjects (CompanyRevision) represented as a non-null FK relationship in the database.
Using LINQ, I want to get all the Companies from the database, but I also only want the latest CompanyRevision for each company.
This is how I do it today, but I have a feeling this could be done using one query.
IEnumerable<Company> companyList = from p in ctx.Company.Include("CompanyRevisions")
select p;
foreach(Company c in companyList)
{
CompanyRevision cr = (from p in c.CompanyRevisions
orderby p.Timestamp descending
select p).First();
// Do something with c and cr...
}
As you can see, I would like to add this second LINQ query (the one that gets the latest CompanyRevision) into the first one, so that companyList[i].CompanyRevisions is basicly a list with just one entry (the latest one). I can't for the life of my figure out how to do this. Please help!
Thanks in advance
how about this: mixing the linq language and extension methods:
var results = from p in ctx.Company.Include("CompanyRevisions")
select new {Company = p,
Revision = p.CompanyRevisions.OrderByDescending(cr => cr.Timestamp).First()
}
Each result now has a Company and Revision member.
It's possible that you could also do this -
var results = from p in ctx.Company.Include("CompanyRevisions")
select new {Company = p,
Revision = (from pcr in p.CompanyRevisions
orderby pcr.Timestamp descending
select pcr).First()
}
To give the same results.
Although that's a guess - I haven't labbed that one out; but it's how I would try it first.

Linq filter collection with EF

I'm trying to get Entity Framework to select an object and filter its collection at the same time. I have a JobSeries object which has a collection of jobs, what I need to do is select a jobseries by ID and filter all the jobs by SendDate but I can't believe how difficult this simple query is!
This is the basic query which works:
var q = from c in KnowledgeStoreEntities.JobSeries
.Include("Jobs.Company")
.Include("Jobs.Status")
.Include("Category")
.Include("Category1")
where c.Id == jobSeriesId
select c;
Any help would be appreciated, I've been trying to find something in google and what I want to do is here:http://blogs.msdn.com/bethmassi/archive/2009/07/16/filtering-entity-framework-collections-in-master-detail-forms.aspx
It's in VB.NET though and I couldn't convert it to C#.
EDIT: I've tried this now and it doesn't work!:
var q = from c in KnowledgeStoreEntities.JobSeries
.Include("Jobs")
.Include("Jobs.Company")
.Include("Jobs.Status")
.Include("Category")
.Include("Category1")
where (c.Id == jobSeriesId & c.Jobs.Any(J => J.ArtworkId == "13"))
select c;
Thanks
Dan
Include can introduce performance problems. Lazy loading is guaranteed to introduce performance problems. Projection is cheap and easy:
var q = from c in KnowledgeStoreEntities.JobSeries
where c.Id == jobSeriesId
select new
{
SeriesName = c.Name,
Jobs = from j in c.Jobs
where j.SendDate == sendDate
select new
{
Name = j.Name
}
CategoryName = c.Category.Name
};
Obviously, I'm guessing at the names. But note:
Filtering works.
SQL is much simpler.
No untyped strings anywhere.
You always get the data you need, without having to specify it in two places (Include and elsewhere).
No bandwith penalties for retrieving columns you don't need.
Free performance boost in EF 4.
The key is to think in LINQ, rather than in SQL or in materializing entire entities for no good reason as you would with older ORMs.
I've long given up on .Include() and implemented Lazy loading for Entity Framework

Resources