Select N Random Rows with Fluent NHibernate - c#

How do I retrieve N random entities using Fluent NHibernate?
Desired query:
SELECT TOP 5 * FROM MyTable ORDER BY newid()
I'd like to be able to use the Linq repo's for this, but I'm not sure if the result will be optimal. I am not familiar with HQL.

SQL Server-specific Solution
Where Word is the random entity:
IQuery q = _unitOfWork.CurrentSession
.CreateQuery("from Word order by newid()")
.SetMaxResults(5);
var randomWords = q.List<Word>();

Side note: FluentNHibernate is not for querying, it is for mapping and configuration only. Querying is part of "pure" NHibernate.
You can't do it using LINQ directly. The function newid() is SQL Server-specific, so there's no direct equivalent in NHibernate. What you can do here is to query using native SQL by using ISession's CreateSQLQuery method.
See also here for more "deep into NHibernate" method:
How do I select a Random Row using NHibernate's ICriteria API?

You can use Take/Skip linq extensions:
var resultSet = session.Query<TestTable>().Skip(5).Take(10);
With PostgreSql DB this expands to the following SQL statement:
select TestTable.Id, TestTable.Field from TestTable
LIMIT :p0 OFFSET :p1;

Related

SQL equivalent of Count extension method for LINQ isn't obvious

I'm doing LINQ to entity framework (EF) to get count of records in my table using below code:
using (var db = new StackOverflowEntities())
{
var empLevelCount = db.employeeLevels.Count();
}
I captured the query fired by EF towards database using SQL Server Profiler. I got the following query :
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[employeeLevels] AS [Extent1]
) AS [GroupBy1]
This query remains exactly the same even for LongCount extension method except for the fact that COUNT SQL function gets replaced by COUNT_BIG in the SQL query being created by EF. The query created by LINQ to EF provider looks very weird to me. Why it is not simply doing something like below to return the scalar count value?
SELECT
COUNT(1) AS [A1]
FROM [dbo].[employeeLevels] AS [Extent1]
It will be really helpful if someone can help me understand the additional logistics being taken care of by EF internally which is why LINQ to EF provider is creating such a query? It seems EF is trying to deal with some additional use cases as well through some common algorithm which results in some sort of generic query as the one created above.
Testing both queries (suitably changing the table) in a DB of mine reveals that they both generate exactly the same query plan. So, the structure shouldn't concern you overly much. In SQL, you tell the system what you want, and it works out how best to do it, and here the optimizer is able to generate the optimal plan given either sample.
As to why LINQ generates code like this, I'd suspect it's just a generalized pattern in its code generator that lets it generate similar code for any aggregation and subsequent transformations, not just for unfiltered counts.

EF sorting results without order by clause

In my asp.net mvc app, I'm using the entity framework to return a list of data. The data returned is in ascending order, even though I don't have an order by clause in my linq statement:
using (TNTContext tnt = new TNTContext())
{
var result = tnt.Wave.Include("Terminals").ToList();
}
I checked sql server profiler and sure enough:
LINQ (or the entity framework I'm not sure which) is by default, ordering my results. Is there a way to turn this off?
If i am not it is doing order by because it is trying to join two tables to fetch the related data
var result = tnt.Wave.Include("Terminals").ToList();
When you say Include it will try to join Wave table with Terminals table and in case of join query is optimized if data is ordered.

How to convert this simple Entity Framework query into a standard SQL query?

I have no experience with the .NET Entity Framework and I have some doubts about what exactly do this query:
using (MyCorpo.EarlyWarnings.Model.EarlyWarningsEntities context = new Model.EarlyWarningsEntities())
{
DBContext.SetTimeout(context);
model.VulnerabilitySeverityAverage = (from x in context.VulnerabilityAlertDocuments select x.Severity).Average();
}
(Where the type of the model.VulnerabilitySeverityAverage is simply a string)
So I think that VulnerabilityAlertDocuments map the VulnerabilityAlertDocument database table because into the EarlyWarningsEntities I have something this line:
public DbSet<VulnerabilityAlertDocument> VulnerabilityAlertDocuments { get; set; }
So I am executing a query on the VulnerabilityAlertDocuments DbSet object that represent a query on my VulnerabilityAlertDocument table on my database. Is it correct?
So what exatly do the previous query?
I think that it select the Severity field value of all records in the VulnerabilityAlertDocument table and calculate the avarage value from all these value.
Is it my reasoning correct?
How can I convert this entity query in a classic SQL query? Someone can help me?
Tnx
How can I convert this entity query in a classic SQL query?
To see actual SQL you can just call .ToString() method on your query;
var sql = (from x in context.VulnerabilityAlertDocuments select x.Severity).Average().ToString();
So I am executing a query on the VulnerabilityAlertDocuments DbSet
object that represent a query on my VulnerabilityAlertDocument table
on my database. Is it correct?
Yes
So what exatly do the previous query?
Your query will average value in Severity column of ValnerabilityAlertDocuments table.
your translated query would've looked simular to this:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
AVG([Extent1].[Severity]) AS [A1]
FROM [dbo].[ValnerabilityAlertDocuments] AS [Extent1]
) AS [GroupBy1]
Also you could try to use such tool as SQL Server Profiler
UPDATE:
Just adding LinqPad to list of tools (thanks to Dismissile)
Select Average(x.Severity)
From VulnerabilityAlertDocuments x
Thats assuming your table is called "VulnerabilityAlertDocuments"
try again

Linq/Entity Framework, performing xpath query on column

We have a database that contains xml fields. At this moment we perform queries on this database that filter on values in the xml. In the near future we would like to migrate to entity framework or NHibernate as orm. Is this possible? This are two of the queries we run (in sql):
SELECT
yy.[Description] as Name,
convert(xml, yy.Xml).value('(//Division)[1]', 'varchar(255)') as Division,
onvert(xml, yy.Xml).value('(//Season)[1]', 'varchar(255)') as Season
into #Statistics .....
And
SELECT [dbo].[yy].[Id]
FROM [dbo].[yy]
WHERE [dbo].[yy].[ApplicationId] = 1
AND (((dbo.[yy].Xml.exist(''(//qq[Season='Non seasonal'])'') = 1)))
Is there anyway to do this?
In EF there are a variety of ways to pass SQL directly through to the server, e.g. ObjectContext.ExecuteStoreQuery. You could also write a stored proc which does the xpath query and map that as usual. There is no native support for xpath in LINQ or Entity SQL, as far as I know.

NHibernate SQLquery for paging to HQL / ICriteria

I'm making a query that sorts and returns X rows based on row_number()
I'm using NHibernate with MSSQL and im trying to get paging working using CreateSQLQuery and i have this query:
select s.*
from(
select distinct release.[stop], survey.SurveyId, survey.Created, survey.CopyOfId, survey.DesignTemplateId, survey.UserId, survey.Template, [Row] = Row_Number() over (order by survey.[SurveyId])
from Survey as survey
inner join Release as release on release.SurveyId = survey.SurveyId
group by survey.SurveyId
, survey.Created
, survey.CopyOfId
, survey.DesignTemplateId
, survey.UserId
, survey.Template
, release.[stop]
) as s
where s.[Row] >= 0 and s.[Row] <= 20
order by s.[stop]
does anyone know how to get this working using HQL or ICriteria (even better) instead of plain SQL? The reason for this is that I want a query that is compatible with both SQLite and MS SQL Server 2005, so that i can use .SetMaxResult() og .SetFirstResult()
Thanks in advance!
Try to avoid using plain SQL in nHibernate.
On Criteria object, use SetFirstResult() and SetMaxResult() for your paging.
Pages of 10 records ? First page is criteria.SetFirstResult(0).SetMaxResult(10) and third page is criteria.SetFirstResult(20).SetMaxResult(10)
Always use the correct dialect. For exemple SQL Server 2008 has more paging features than SQL Server 2005.
Here's an excellent article to do what you want
http://www.tobinharris.com/past/2008/10/20/almost-iqueryable-with-nhibernate-hql/

Categories