According to this issue:
https://nhibernate.jira.com/browse/NH-3038
NHibernate should create efficient paging queries for SQL Server 2012.
I have NHibernate 3.3.3GA. I set the dialect in the config file:
<property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
and while debugging I see that indeed the session factory has MsSql2012Dialect.
But still the following code:
session.Query<TestEntity>().Skip(1).Take(1).ToList()
generates the same T-SQL as the old SQL Server 2008 dialect does:
exec sp_executesql N'
SELECT TOP (#p0) EntityId1_, Version1_, Name1_, Something1_
FROM (select testentity0_.EntityId as EntityId1_, testentity0_.Version as Version1_, testentity0_.Name as Name1_, testentity0_.Something as Something1_, ROW_NUMBER()
OVER(ORDER BY CURRENT_TIMESTAMP)
as __hibernate_sort_row from tTestEntity testentity0_) as query
WHERE query.__hibernate_sort_row > #p1
ORDER BY query.__hibernate_sort_row',N'#p0 int,#p1 int',#p0=1,#p1=1
How do I make NHibernate Linq provider to use the paging features of MsSql2012Dialect and generate a query with OFFSET and FETCH?
Solution:
Thanks to Diego Mijelshon who led me to the right source code, I managed to implement a quick fix which seems to work fine. We are using it for some months already, no problems yet.
Here is what I did:
I imported the following classes from the NHibernate source into my own library:
https://github.com/nhibernate/nhibernate-core/blob/967091f5c22a16a576f46144055f78c0f373ffcd/src/NHibernate/SqlCommand/Parser/SqlTokenizerExtensions.cs
https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Dialect/MsSql2012Dialect.cs
https://github.com/nhibernate/nhibernate-core/blob/967091f5c22a16a576f46144055f78c0f373ffcd/src/NHibernate/SqlCommand/Parser/SqlTokenizer.cs
https://github.com/nhibernate/nhibernate-core/blob/967091f5c22a16a576f46144055f78c0f373ffcd/src/NHibernate/SqlCommand/Parser/SqlParserUtils.cs
https://github.com/nhibernate/nhibernate-core/blob/967091f5c22a16a576f46144055f78c0f373ffcd/src/NHibernate/SqlCommand/Parser/SqlToken.cs
As far as I remember, I did some modifications to remove unnecessary bits of code.
In SqlTokenizerExtensions I left only these two extensions:
public static bool TryParseUntil(this IEnumerator<SqlToken> tokenEnum, string keyword)
public static bool TryParseUntilFirstMsSqlSelectColumn(this IEnumerator<SqlToken> tokenEnum)
SqlTokenizer, SqlToken, SqlParserUtils, MsSql2012Dialect - no changes.
Then I just set <property name="dialect"> to the new MsSql2012Dialect in my config file for NHibernate, and now my paging queries are clean and simple.
If you look at NH-3038, you'll see that it's fixed in master/vNext. That means NH4.
You can still get the updated dialect from https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Dialect/MsSql2012Dialect.cs, include it in your project and reference it (adding the correct assembly name).
Related
I adapted my code from the instructions here.
open FSharp.Data.Sql
let [<Literal>] connection_str = "Server=localhost;Port=3306;SSL Mode=None;Uid=<UID>;Pwd=<PWD>;Database=<DB>"
type provider = SqlDataProvider<Common.DatabaseProviderTypes.MYSQL, connection_str>
let context = provider.GetDataContext()
context.Procedures.SpGetFrontContracts.Invoke(1)
Intellisense works until the period after SpGetFrontContracts. After that, nothing. Trying to compile, I get:
Error FS0039 The field, constructor or member 'Invoke' is not defined.
I am otherwise able to connect to the database and insert and query data, as long as I stick to tables and views.
SpGetFrontContracts is a valid stored procedure in my database (its actual name is sp_get_front_contracts, but the type provider seems to remove underscores). I can run it successfully using HeidiSQL. In case it's useful, here's the create code:
CREATE DEFINER=`<UID>`#`localhost` PROCEDURE `sp_get_front_contracts`(
IN `Group` INT
)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
SELECT p.DateTime, p.Contract, p.Volume, c.Name
FROM tbl_contract_price_data p
INNER JOIN tbl_contracts c on p.Contract = c.ID
WHERE c.`Group` = `Group`
ORDER BY p.DateTime
LIMIT 1000;
END
I tried creating a simpler sproc that was named 'test', took no parameters, and simply ran a select statement. It showed up in the type provider under Procedures, but again I could not call Invoke on it.
My best guess is that Invoke is being inherited from some namespace or assembly reference I don't have, so I'm currently looking through the SqlProvider source to try to figure out what it might be. I'm currently referencing:
FSharp.Core
FSharp.Data
FSharp.Data.SqlProvider
mscorlib
System
System.Core
System.Data
System.Numerics
System.ValueTyple
System.Xml.Linq
Thank you for any suggestions.
Edit: It looks like the action is in SqlDesignTime.fs in a function called generateSprocMethod that starts on line 346. I'll try to figure out what's going on in there.
Edit: After three days banging my head against this, I gave up and just used MySQL Connector/NET.
I'm not sure about your underlying data or structures, but I know these are two other (correct) ways to solve it:
WHERE c.`Group` = `Group` -- what you have.
-- possible corrections:
WHERE c.`Group` = p.`Group` -- did you mean this?
WHERE c.`Group` = "Group" -- or this?
Is there are way to detect what type of database currenlty is in use as project datasource?
Because I need to get some inner scripts information. And, in case of simple .EAP project, SQL-query would look like (because of Access db in use):
_repository.SQLQuery(string.Format(#"SELECT * FROM t_script WHERE Notes LIKE '*Script Name=""{0}""*';", scriptName));
But, in case of SQL server I need to execute (as you already guessed I bet) slighly different written query:
_repository.SQLQuery(string.Format(#"SELECT * FROM t_script WHERE Notes LIKE '%Script Name=""{0}""%';", scriptName));
So, is it possible?
UPD:
I found one option - looks like there are _repository.ConnectionString property which could be parsed
"SparxEaDatabase --- DBType=1;Connect=Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SparxEaDatabase;Data Source=SOURCENAME;LazyLoad=1;"
Is there are more?
I would just look into Repository.RepositoryType. This will return for Example: JET, MYSQL, or SQLSVR.
How is the IFNULL of SQL implemented in Symfony2 Doctrine Query Builder?
Let's say I have this query:
select * from ticket order by IFNULL(modified_date, '2000-01-01') DESC, created_date DESC
I have this DQL:
$this->qb->select("t, c.name")
->from("Ticket", "t");
$this->qb->orderBy("t.modifiedDate", "DESC");
$this->qb->addOrderBy("t.createdDate", "DESC");
Now how to add the IFNULL part?
Ok, done some research and found that there is no such implementation.
Googled a little more, and got that this kind of missing features can be added to Doctrine as own functions.
Found this extension on GitHub I think this will work. But wonder if ther would be any problems or conflicts with Doctrine versions...
This is the valid link with the DQL Extension
Edit with the solution explained:
Create the following directory under your project src path: /src/DoctrineExtensions/Query/Mysql
Put there the DQL Extension file (IfNull.php in this case)
Edit your src/config/packages/doctrine.yaml and insert this new lines:
doctrine:
...
orm:
...
dql:
numeric_functions:
IFNULL: App\DoctrineExtensions\Query\Mysql\IfNull
In your entity repository you can call this function like this:
$qb = $this->createQueryBuilder('tl')
->andWhere('IFNULL(tl.app,0) = 1');
Depending on your usecase you may be able to use the builtin "COALESCE" expression instead of installing the "IFNULL" extension.
The usage then is basically the same as with the IFNULL expression.
Just replace IFNULL with COALESCE in the example in https://stackoverflow.com/a/68827681/1707003.
Note: COALESCE might behave slightly different than IFNULL depending on your database. https://stackoverflow.com/a/18528590/1707003 contains some great explanations.
List of builtin case-expressions: https://www.doctrine-project.org/projects/doctrine-orm/en/2.13/reference/dql-doctrine-query-language.html#case-expressions
I have sample application on Nhibernate with Nhibernate Search with the following version nos,
Nhibernate - v2.0.0.1001
Nhibernate Search - v2.0.0.1001
I am not sure if it custom build, but everything seems to work fine here. But as soon as I change the Nhibernate version to v2.0.1.4000 (a later minor version and build), things start breaking at,
IList result = s.CreateCriteria(typeof(DomainObject)).Add(NHibernate.Search.Search.Query("Summary:NHibernate or Name:NHibernate"))
VStudio complains "'Query' is not supported language."
Has anyone had a similar issue? How could I get a port for v2.0.1.4000?
Thanks.
I guess the way to create a lucene query was to just use the Query Parser:
QueryParser queryP = new QueryParser("id", new StandardAnalyzer());
Lucene.Net.Search.Query q = queryP.Parse("Summary:NHibernate or Name:NHibernate");
IList result = s.CreateFullTextQuery(q, typeof(DomainObject)).List();
I'm using IdeaBlade version 3.6. I noticed the following generated SQL update query :
(#P1 nchar(32),#P2 nvarchar(32),#P3 nvarchar(512),#P4 nchar(32),#P5 int,#P6 nvarchar(32),#P7 int,#P8 datetime,#P9 datetime,#P10 datetime,#P11 int,#P12 datetime,#P13 int,#P14 int,#P15 int,#P16 nvarchar(32),#P17 nvarchar(128),#P18 nvarchar(32),#P19 nvarchar(32),#P20 datetime,#P21 datetime,#P22 bit,#P23 nvarchar(32),#P24 nvarchar(64),#P25 nchar(32))update "dbo"."GSS_Documents" set "DocumentID"=#P1,"FileName"=#P2,"FilePath"=#P3,"BusinessOfficeID"=#P4,"Pages"=#P5,"FileSize"=#P6,"DocumentType"=#P7,"DateCreated"=#P8,"EffectiveDateCreated"=#P9,"DateProcessed"=#P10,"ProcessorID"=#P11,"DateReviewed"=#P12,"ReviewerID"=#P13,"WorkflowStatus"=#P14,"ApprovalStatus"=#P15,"AccountNumber"=#P16,"AccountName"=#P17,"SerialNumber"=#P18,"TransactionID"=#P19,"CriticalDate"=#P20,"EmergencyDate"=#P21,"GenerateSMSAlert"=#P22,"CustomerPhoneNumber"=#P23,"CustomerEmailAddress"=#P24 where "DocumentID"=#P25
Problem is DocumentID is the primary key. This update appears to be updating the primary key as well! Any ideas on how to stop this?
You're using Entity Framework in this example and we don't tell EF how to do its job. Perhaps you're changing the PK (I rather doubt it). Follow up with us directly ... especially with regard to DevForce 2010 which relies on EF v.4.