I just started with NHibernate (using SQLite) in my current project and I mostly used Query<>, because I was familiar writing db queries in Linq.
When I was confronted with some more complex queries, I did some research on QueryOver<> and figured that it should be favored over Query<> because "QueryOver syntax is NH specific". Also, there seems to be nothing that Query<> can do that QueryOver<> can't accomplish.
So I began replacing all usages of Query<> accordingly. It wasn't long before I had the first "issue" where using Query<> seemed just more convenient.
Example (select highest value from column CustomNumber in table BillingDataEntity):
int result = Session.Query<BillingDataEntity>().Select(x => x.CustomNumber).OrderByDescending(a => a).FirstOrDefault();
int result = Session.QueryOver<BillingDataEntity>().Select(x => x.CustomNumber).OrderBy(a => a.CustomNumber).Desc.Take(1).SingleOrDefault<int>();
What I dislike is the need to explicitly cast the result to int and that the the Query<> version is just easier to read. Am i getting the query totally wrong, or in other words: Is there a better way to do it?
I took a look at the generated SQL output:
NHibernate: select billingdat0_.CustomNumber as col_0_0_ from "BillingDataEntity" billingdat0_ order by billingdat0_.CustomNumber desc limit 1
NHibernate: SELECT this_.CustomNumber as y0_ FROM "BillingDataEntity" this_ ORDER BY this_.CustomNumber desc limit #p0;#p0 = 1 [Type: Int32 (0)]
What exactly am i looking at? Is this the "internal" (method dependent) query that NHibernate further translates into the actual database query?
There are plenty of answers regarding QueryOver versus Query here on Stackoverflow but in a nutshell:-
QueryOver is a strongly-typed version of Criteria, and is more
NHibernate specific. Pretty much anything you can do in ICriteria can
be done with QueryOver. In the golden days of ICriteria NH2 you always had
to cast, hence this is why now you need to cast at the end of the
chain back to an int.
LINQ (Query) is a standard query method that works on IQueryable that
doesn't need explicit references to NHibernate and can be considered
more ORM agnostic and therefore follows the linq standard. As you
rightly pointed out you do not need to cast to an int as you are
selecting into the result the customNumber.
I would be very surprised for your simple example if the generated SQL was very different.
I was a big fan of QueryOver but as the Linq provider is getting more mature then 95% of my queries I use Query but for some Nhibernate specific stuff I resort back down to QueryOver. Either way I recommend using a profiling tool to see what you can live with.
Refs: Tradeoffs or versus and versus
About your QueryOver version, I would have written :
int result = Session.QueryOver<BillingDataEntity>()
.Select(Projections.Max<BillingDataEntity>(x => x.CustomNumber))
.SingleOrDefault<int>();
It seems quite readable, and the resulting SQL would be something like :
SELECT max(this_.CustomNumber) as y0_ FROM "BillingDataEntity" this_
Hope this will help
Related
I want to execute a complex query using Entity Framework (Code First).
I know it can be done by LINQ, but what is the best way to write LINQ query for complex data and inner joining?
I want to execute the following query:
var v = from m in WebAppDbContext.UserSessionTokens
from c in WebAppDbContext.Companies.Include(a => a.SecurityGroups)
from n in WebAppDbContext.SecurityGroups.Include(x => x.Members)
where m.TokenString == userTokenString &&
n.Members.Contains(m.User) &&
c.SecurityGroups.Contains(n)
select c;
Is this the best way to do this?
Does this query get any entire list of records from the db and then executes the filtration on this list? (might be huge list)
And most important: Does it query the database several times?
In my opinion and based on my own experiences, talking about performance, especially joining data sets, it's faster when you write it in SQL. But since you used code first approach then it's not an option. To answer your questions, your query will not query DB several times (you can try debugging and see Events log in VS). EF will transform your query into SQL statement and execute it.
TL:DR; don't micromanage the robots. Let them do their thing and 99% of the time you'll be fine. Linq doesn't really expose methods to micromanage the underlying data query, anyway, its whole purpose is to be an abstraction layer.
In my experience, the Linq provider is pretty smart about converting valid Linq syntax into "pretty good" SQL. Your looks like your query is all inner joins, and those should all be on the primary indexes/foreign keys of each table, so it's going to come up with something pretty good.
If that's not enough to soothe your worries, I'd suggest:
put on a SQL Trace to see the actual query that's being presented to the Database. I bet it's not as simple as Companies join SecurityGroups join Members join UserTokens, but it's probably equivalent to it.
Only worry about optimizing if this becomes an actual performance problem.
If it does become a performance problem, consider refactoring your problem space. It looks like you're trying to get a Company record from a UserToken, by going through three other tables. Is it possible to just relate Users and Companies directly, rather than through the security model? (please excuse my total ignorance of your problem space, I'm just saying "maybe look at the problem from another angle?")
In short, it sounds like you're burning brain cycles attempting to optimize something prematurely. Now, it's reasonable to think if there is a performance problem, this section of the code could be responsible, but that would only be noticeable if you're doing this query a lot. Based on coming from a security token, I'd guess you're doing this once per session to get the current user's contextual information. In that case, the problem isn't usually with Linq, but with your approach to solving the problem for finding Company information. Can you cache the result?
I have an app using Entity Framework. I want to add a tree view listing products, grouped by their categories. I have an old SQL query that will grab all of the products and categories and arrange them into parent nodes and children. I am trying to translate it into LINQ that uses the EF. But the SQL has a WITH sub-query that I am not familiar with using. I have tried using Linqer and LinqPad to sort it out, but they choke on the WITH clause and I am not sure how to fix it. Is this sort of thing possible in LINQ?
Here is the query:
declare #id int
set #id=0
WITH ChildIDs(id,parentid,type,ChildLevel) AS
(
SELECT id,parentid,type,0 AS ChildLevel
FROM dbo.brooks_product
WHERE id = #id
UNION ALL
SELECT e.id,e.parentid,e.type,ChildLevel + 1
FROM dbo.brooks_product AS e
INNER JOIN ChildIDs AS d
ON e.parentid = d.id
WHERE showitem='yes' AND tribflag=1
)
SELECT ID,parentid,type,ChildLevel
FROM ChildIDs
WHERE type in('product','productchild','productgroup','menu')
ORDER BY ChildLevel, type
OPTION (MAXRECURSION 10);
When I run the query, I get data that looks like this (a few thousand rows, truncated here):
ID.....parentid.....type.....ChildLevel
35429..0............menu.....1
49205..0............menu.....1
49206..49205........menu.....2
169999.49206........product..3
160531.169999.......productchild..4
and so on.
The WITH block is a Common Table Expression, and in this case is used to create a recursive query.
This will be VERY difficult in Linq as Linq doesn't play well with recursion. If you need all of the data on one result set that a Stored Procedure would be easier. Another option is to do the recursion in C# (not in Linq but a recursive function) and do multiple round-trips. The performance will not be as good but if you result set is small it may not make much difference (and you will get a better object model).
You may be able to solve this using LINQ to Entities, but it is non-trivial and I suspect it will be very time consuming.
In situations like this, you may prefer to build a SQL View or Table-Valued Function that returns the results for which you're looking. Then import that View or Table-Valued Function into your EF model and you can pull data directly from it using LINQ.
Querying the View in LINQ is no different than querying a table.
To get data from a Table-Valued Function in LINQ, you pass the function's parameters in after the name of the function, like so:
var query = from tvf in _db.MyTableValuedFunction(parameters)
select tvf;
EDIT
As suggested by #thepirat000, Table-Valued Function support is not available in Entity Framework versions prior to version 5. In order to use this functionality, EF must be running with .NET 4.5 or higher.
At the end of the day, I could not get this to work. I ended up writing out a SQL query dynamically and sending that straight to the database. It works fine, and I am not relying on any direct user input so there is no chance of SQL injection. But it seems so old school! For the rest of my program I am using EF and LINQ.
Thanks for the replies!
I'm having trouble understanding why the SQL output has a sub-query for a simple query I wrote in LINQ. This is my code:
var list = db.User.Where(u => u.Name == somename).OrderBy(u => u.IdUser).ToList();
where somename is a parameter I'm passing at execution time.
The output SQL is:
SELECT
Project1.IdUser,
Project1.Name
FROM (SELECT
Extent1.IdUser,
Extent1.Name
FROM user AS Extent1
WHERE Extent1.Name = 'John' /* #p__linq__0 */) AS Project1
ORDER BY
Project1.IdUser ASC
Should the output really have a sub-query for something that simple?
I also tried
var list = db.User.Where(u => u.Name.Equals(somename)).OrderBy(u => u.IdUser).ToList();
which generates the same output as above.
If I hard code the parameter, like:
var list = db.User.Where(u => u.Name == "John").OrderBy(u => u.IdUser).ToList();
It works as expected, generating only
SELECT
Extent1.IdUser,
Extent1.Name
FROM user AS Extent1
WHERE 'John' /* #gp1 */ = Extent1.Name
ORDER BY
Extent1.IdUser ASC
A few things I'm using:
EntityFramework 5, .NET 4.5
SQL Server 2012
Glimpse (which uses MiniProfiler) to see the SQL generated
I'm not a LINQ expert, so what am I missing here?
As other pointed, the query results in same execution plan as yours. Entity Framework (and LINQ to Entites) is here to help you avoid writing SQL and bothering about SQL (to some extent). Under normal circumstances you don't care about SQL being generated nor you "debug" it. You just care whether the LINQ query is correct. Entity Framework (should) translates it into correct (sometimes even expected) SQL (and again, execution plan matters).
I'm not saying that you shouldn't look at SQL for performance reasons (or better to say execution plan of that query). But that should be done after you identified performance problems. And you should try to write queries simple first, that's the way to success. Of course if you know SQL you know this world of sets is different from world of object - you can write easily fairly average query in LINQ (thanks to objects world), but this will end up as nasty SQL (sets world) because of "mismatch" between worlds.
My current database solution includes three tables called Establishment, Feature, and a linking many-to-many table called EstablishmentFeature (since an establishment can have many features, and a feature can exists across multiple establishments).
I need to generate a query that returns establishments that meet only certain criteria, namely, which establishments have X features based on a collection of featureId's being passed in. The establishment must have ALL features that are being search, i.e.. AND not OR condition.
I got the SQL to achieve the desired result, but I am pulling my hair out trying to work out the LINQ (lambra prefereably) equivalent. The T-SQL is:
SELECT e.[EstablishmentId], e.[Name], e.[Description]
FROM Establishment e
INNER JOIN EstablishmentFeature ef
ON e.[EstablishmentId] = ef.[EstablishmentId]
WHERE ef.[FeatureId] in ('20', '15', '72')
GROUP BY e.[EstablishmentId], e.[Name], e.[Description]
HAVING COUNT(*) = 3
I tried to use Linqer to convert the SQL but Linqer crashes when it attempts the conversion. I tried reinstalling Linqer, but it crashes without fail when trying to compile the LINQ syntax. (Simpler conversions work though). Also tried to work out the LINQ equivalent using LinqPad, but I just ended up chasing my tail...
Is this something I will have to use PredicateBuilder for? Somewhat exhausted, I don't want to go through the PredicateBuilder learning curve if there is a simple solution that is escaping me.
I'd try this (For all given ids there is any (= at least one) feature that has this given id):
var establishments = context.Establishments
.Where(e => featureIds.All(fid => e.Features.Any(f => f.FeatureId == fid)))
.ToList();
(featureIds is an IEnumerable<int> with the Ids being searched for.)
I'm fairly new to nHibernate having come from an EF background and I'm struggling with the following query :
_patientSearchResultModel = (from patient in _patientRepository.Query(patientSearch.BuildPatientSpecification())
join admission in _admissionRepository.Query(patientSearch.BuildAdmissionSpecification())
on patient.Id equals admission.Patient.Id
orderby admission.AdmissionDate
select new PatientSearchResultModel(patient.Id,
admission.Id,
false,
_phaseTypeMapper.GetPhaseTypeModel(admission.PhaseType),
patient.Last, patient.First,
admission.InPatientLocation,
admission.AdmissionDate,
admission.DischargeDate,
admission.RRI,
null,
admission.CompletionStatus,
admission.FollowupStatus)).ToList();
The intent of this query is to allow users to filter the two queries on parameters built up using the two Build???Specification functions and return the resultset. There could be many admission records and I would only like one PatientSearchResultModel per patient object, with the admission object being the newest one by Admission Date.
These objects are coming from nHibernate and it keeps return a Not Supported exception. There is also an association between Patient and Admissions thus : Patient.Admissions but i couldn't figure out how to then add the query filters return from the function Build???Specifications.
I'd be really grateful if someone could point me in the right direction; am I up against the Linq provider implementation here in nHibernate and need to move to Criteria or is it my Linq query ?
If anyone has any links or suggestions for good books or other learning materials in this area that would also be really helpful too.
I see several potential problems:
If you're using NHibernate 2.x + Linq2NHibernate explicit joins like that are not supported; in other versions they're just considered a smell.
I dont think NHibernate supports calling parameterized constructors in select clauses
I'm very sure NHibernate does not support calling instance methods in the select lambda
I'd suggest using the lambda syntax and SelectMany to alleviate potential join issues. Points #2 & #3 can be solved by projecting into an anonymous type, calling AsEnumerable then projecting into your model type.
Overall I'd suggest restructuring your code like:
var patientSpec = patientSearch.BuildPatientSpecification();
var admissionSpec = patientSearch.BuildAdmissionSpecification();
_patientSearchResultModel = _patientRepository.Where(patientSpec)
.SelectMany(p=>p.Admissions).Where(admissionSpec)
.Select(a=> new {
PatientId = a.Patient.Id,
AdminssionId = a.Id,
a.PhaseType,
a.Patient.Last,
a.Patient.First,
a.InPatientLocation,
a.AdmissionDate,
a.DischargeDate,
a.RRI,
a.CompletionStatus,
a.FollowupStatus
}).AsEnumerable()
.Select(x=> new PatientSearchResultModel(x.PatientId, x.AdmissionId ...))
.ToList();
Divide your query into parts and check which part runs and which doesn't.
My take on this is that select new ... is not supported in Linq to nHibernate.
I would recomend using something else, because it is simply too imature and feature-less to use seriously.
As with most popular LINQ-to-Database query providers, NHibernate will try to translate the whole query into a SQL statement to run against the database. This requires that all elements of your query are possible to express in the SQL flavour you're using.
In your query, the select new statement cannot be expressed in SQL, because you're making a call to the constructor of your PatientSearchResultModel class and are making a call to a GetPhaseTypeModel method.
You should restructure your query to express what you want to execute on the SQL database, then call AsEnumerable() to force the remainder of the query to be evaluated in-memory. After that call, you can call the constructor of your class and any .NET methods, and they will be executed as native code.
This query is too complex to describe it using Linq. It would give wrong result finally (if Patient has more than one admission records, result would have duplicate entries).
I see two steps for solution:
1) At development stage, use in-memory query. So, take Patients using ToList() first (query db at this moment). Some predicates (Patient filter like MRN, First, Last) could be used at this stage.
And then do search in-memory. Not performance, but working solution. Mark it for refactor to optimize later.
2) Finally, use NHibernate IQuery (ISQLQuery) and build sql query manually to make sure it would work as expected and work fast enough on SQL Server side. This is just read-only query and do not require Nhibernate query engine (Linq to Nhibernate) at all.