Piani di esecuzione generati da SQLServer

60 views
Skip to first unread message

makka <Claudio Maccari/>

unread,
Mar 3, 2009, 12:29:42 PM3/3/09
to NHibernate-It
Mi trovo davanti ad un problema con i piani di esecuzione generati da
SQLServer come descritto qui
http://forum.hibernate.org/viewtopic.php?p=2385009#2385009
ed anche qui
http://blogs.ugidotnet.org/rcappe/archive/2009/02/21/nhibernate-e-piani-di-esecuzione.aspx

Ora il campo è mappato così:
Map(x => x.Description)
.SetAttributes(new Attributes { { "type", "System.String" },
{ "length", "20" } });

ma questo è il risultato purtroppo è questo:
exec sp_executesql N'select municipali0_.Description as x0_0_ from
municipalities municipali0_ where (municipali0_.Description like
@p0 )',N'@p0 nvarchar(4)',@p0=N'aos%'

exec sp_executesql N'select municipali0_.Description as x0_0_ from
municipalities municipali0_ where (municipali0_.Description like
@p0 )',N'@p0 nvarchar(5)',@p0=N'geno%'

Qualcuno ha una soluzione a questo problema ?
Grazie
claudio

Fabio Maulo

unread,
Mar 3, 2009, 12:33:53 PM3/3/09
to nh...@googlegroups.com
Mi sá tanto che se usi il mapping XML funziona correttamente.

2009/3/3 makka <Claudio Maccari/> <claudio...@gmail.com>



--
Fabio Maulo

makka <Claudio Maccari/>

unread,
Mar 3, 2009, 2:46:54 PM3/3/09
to NHibernate-It
Purtroppo no!
Ho fatto questa rapida prova che usa il mapping via xml:
*********** Mapping ***********
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="demo"
assembly="demo">
<class name="Region" table="Region" lazy="false">
<id name="Id" column="RegionId" >
<generator class="identity" />
</id>
<property name="Description">
<column length="50" sql-type="varchar" name="RegionDescription"/
>
</property>
</class>
</hibernate-mapping>

*********** Configurazione ***********
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.connection_string">Data Source=.
\SQLEXPRESS;Database=Northwind;Trusted_Connection=yes;</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</
property>
<property
name="connection.provider">NHibernate.Connection.DriverConnectionProvider</
property>
<property
name="connection.driver_class">NHibernate.Driver.SqlClientDriver</
property>
<property name="show_sql">false</property>
<property name="connection.release_mode">auto</property>
<property name="adonet.batch_size">500</property>

<!-- Mapping assemblies -->
<mapping assembly="demo"/>
</session-factory>
</hibernate-configuration>


*********** Applicazione ***********
using System;
using NHibernate;
using NHibernate.Cfg;

namespace demo
{
class Program
{
static void Main(string[] args)
{
var configuration = new Configuration();
configuration.Configure("hibernate.cfg.xml");
ISessionFactory factory = configuration.BuildSessionFactory
();
using (ISession session = factory.OpenSession())
{
IQuery q1 = session.CreateQuery("from Region r where
r.Description like :desc");
q1.SetParameter("desc", "zon%");
q1.List();

IQuery q2 = session.CreateQuery("from Region r where
r.Description like :desc");
q2.SetParameter("desc", "zone%");
q2.List();
}

Console.Read();
}
}

public class Region
{
public virtual int Id { get; set; }
public virtual string Description { get; set; }
}
}

Le query eseguite sono:
exec sp_executesql N'select region0_.RegionId as RegionId0_,
region0_.RegionDescription as RegionDe2_0_ from Region region0_ where
(region0_.RegionDescription like @p0 )',N'@p0 nvarchar(4)',@p0=N'zon%'
exec sp_executesql N'select region0_.RegionId as RegionId0_,
region0_.RegionDescription as RegionDe2_0_ from Region region0_ where
(region0_.RegionDescription like @p0 )',N'@p0 nvarchar(5)',@p0=N'zone
%'

C'è qlc di sbagliato nel mio mapping ?
Grazie
Claudio

Fabio Maulo

unread,
Mar 3, 2009, 2:58:56 PM3/3/09
to nh...@googlegroups.com
Fai questa

<property name="Description" length="50">

senza niente altro per quella propietá.

Non puoi mica fare la prova usando il mapping che genera FNH altrimenti sei punto e accapo.


2009/3/3 makka <Claudio Maccari/> <claudio...@gmail.com>



--
Fabio Maulo

makka <Claudio Maccari/>

unread,
Mar 3, 2009, 3:06:18 PM3/3/09
to NHibernate-It
Ora il mapping è semplicemente
<property name="Description" length="50" column="RegionDescription" />

Purtropppo il risultato sempre

Fabio Maulo

unread,
Mar 3, 2009, 3:20:04 PM3/3/09
to nh...@googlegroups.com
Se é un bug, c'é il JIRA che ancora funziona.

2009/3/3 makka <Claudio Maccari/> <claudio...@gmail.com>



--
Fabio Maulo

Fabio Maulo

unread,
Mar 3, 2009, 3:24:41 PM3/3/09
to nh...@googlegroups.com
Ah... una cosa
usa il metodo apposito per string nel IQuery

2009/3/3 Fabio Maulo <fabio...@gmail.com>



--
Fabio Maulo

Fabio Maulo

unread,
Mar 3, 2009, 3:30:43 PM3/3/09
to nh...@googlegroups.com
Anche se in questo caso non riconosce automaticamente la lunghezza del parametro perché non la configura a secondo della propietá.
Hai un overload che ti permette passare un IType e in quel caso la lunghezza del parametro é specificata e quindi la usa.

La lunghezza dei parametri é usata da NH quando genera le query di Insert e Update. Nelle query dovresti usare un IType... potrei sbagliarmi ma mi sa che é cosí.

Prima non avevo letto bene tutto il thread e siccome só che da quando sono stati scritti i nuovi Binders su NH1.2.0 si sono introdotti una serie di problemi poco conosciuti, pensavo che mostrassi l'esecuzione delle query autogenerate.
Scusa per il disguido.

2009/3/3 Fabio Maulo <fabio...@gmail.com>



--
Fabio Maulo

makka <Claudio Maccari/>

unread,
Mar 3, 2009, 3:41:08 PM3/3/09
to NHibernate-It
Fabio, no problem.
non devi scusarti di nulla!

Ora faccio queste 3 query

session.CreateQuery("from Region r where r.Description
like :desc")
.SetString("desc", "zon%")
.List();

session.CreateQuery("from Region r where r.Description
like :desc")
.SetParameter("desc", "zone%")
.List();

session.CreateQuery("from Region r where r.Description
like :desc")
.SetParameter("desc", "zoneh%", new
FixedLengthString(50))
.List();

ma tutte usano il parametro con tipo e lunghezza non corretti.
Per fare le cose giuste il parametro dovrebbe essere varchar(50)

Il tipo FixedLengthString è un mio tipo così definito:

public class FixedLengthString : AbstractStringType
{
public FixedLengthString(int length)
: base(new StringSqlType(length))
{
}

public override string Name
{
get { return "String"; }
}
}

speravo che questo potesse aiutare ma nn è così.
Forse devo modificare la mia implementazione di FixedLengthString ?
Grazie
Claudio

makka <Claudio Maccari/>

unread,
Mar 3, 2009, 3:43:36 PM3/3/09
to NHibernate-It
Anche questa implementazione di FixedLengthString non funziona

public class FixedLengthString : AbstractStringType
{
public FixedLengthString(int length)
: base(new StringFixedLengthSqlType(length))

Fabio Maulo

unread,
Mar 3, 2009, 4:40:38 PM3/3/09
to nh...@googlegroups.com
Stanotte ci guardo.
La lunghezza é una responsabilitá del Driver ed é stata introdotta propio per MsSQL, poi guardo da dove cacchio la prende.

2009/3/3 makka <Claudio Maccari/> <claudio...@gmail.com>



--
Fabio Maulo

makka <Claudio Maccari/>

unread,
Mar 3, 2009, 5:34:22 PM3/3/09
to NHibernate-It
Fabio,
andando di debug ho scoperto che SqlClientDriver ha la proprietà
IsPrepareSqlEnabled
(da abilitare con <property name="prepare_sql">true</property> nel
file di config)
Impostando questo parametro ho il seguente comportamento

la sintassi
session.CreateQuery("from Region r where r.Description like :desc")
.SetString("desc", "zon%")
.List();
usa un parametro di tipo
nvarchar(4000)

la sintassi
session.CreateQuery("from Region r where r.Description like :desc")
.SetParameter("desc", "zone%")
.List();
usa un parametro di tipo
nvarchar(4000)

la sintassi
session.CreateQuery("from Region r where r.Description like :desc")
.SetParameter("desc", "zoneh%", TypeFactory.GetStringType(50))
.List();
usa un parametro di tipo
nvarchar(50)

la sintassi
session.CreateQuery("from Region r where r.Description like :desc")
.SetParameter("desc", "z%", TypeFactory.GetAnsiStringType(50))
.List();
usa un parametro di tipo
varchar(50)

Mi confermi che IsPrepareSqlEnabled non serve ad altro e quindi lo
posso lasciare abilitato senza problemi ?
Grazie mille
Claudio

Fabio Maulo

unread,
Mar 3, 2009, 8:53:57 PM3/3/09
to nh...@googlegroups.com
Se non ricordo male il defaul di quel parametro era lasciato al Dialect, che strano che sia false per MsSQL.

2009/3/3 makka <Claudio Maccari/> <claudio...@gmail.com>



--
Fabio Maulo

Fabio Maulo

unread,
Mar 4, 2009, 7:01:57 AM3/4/09
to nh...@googlegroups.com
Allora...
é quella cosa lí che hai trovato peró
DefaultProperties[Environment.PrepareSql] = "false";
questo stá nel dialect di MsSQL ossia che esplicitamente é messo a false di default... 

2009/3/3 Fabio Maulo <fabio...@gmail.com>



--
Fabio Maulo

makka <Claudio Maccari/>

unread,
Mar 4, 2009, 2:42:03 PM3/4/09
to NHibernate-It
Strano che sia false visto che viene solo usato
da DriverBase.IsPrepareSqlEnabled che poi viene utilizzato solo in
SqlClientDriver
nel metodo SetParameterSizes

Un domanda però. Perchè il valore di lenght non viene usato dal metodo
SetParameterSizes ?
Nel mio esempio ho questo mapping
<property name="Description" length="50" column="RegionDescription" />

se uso la sintassi
session.CreateQuery("from Region r where r.Description like :desc")
.SetParameter("desc", "zone%")
.List();
usa un parametro di tipo nvarchar(4000)
A cosa serve l'attributo lenght ?




Fabio Maulo

unread,
Mar 4, 2009, 2:46:41 PM3/4/09
to nh...@googlegroups.com
il primo é il length della propietá e viene sempre usato correttamente nei INSERT e UPDATE.
Il secondo é il length che potrebbe essere associato a qualchier cosa...

from Region r where r.Description like :pStart + :desc + :pEnd

Che lunghezza dobrebbe avere ogni parametro ?
Beh lí trovi il motivo.

2009/3/4 makka <Claudio Maccari/> <claudio...@gmail.com>



--
Fabio Maulo

makka <Claudio Maccari/>

unread,
Mar 4, 2009, 3:06:06 PM3/4/09
to NHibernate-It
Io vedo che l'istruzione
using (ISession session = factory.OpenSession())
{
Region region = new Region { Id = 6, Description =
"Insert" };
session.Save(region);
session.Flush();
}
genera il comando SQL:

exec sp_executesql N'INSERT INTO Region (RegionDescription, RegionId)
VALUES (@p0, @p1)',N'@p0 nvarchar(6),@p1 int',@p0=N'Insert',@p1=6

quindi INSERT NON USA il lenght del mapping

Io vedo che l'istruzione
using (ISession session = factory.OpenSession())
{
Region region = new Region { Id = 6, Description =
"Item updated with a new value" };
session.Update(region);
session.Flush();
}
genera il comando SQL:

exec sp_executesql N'UPDATE Region SET RegionDescription = @p0 WHERE
RegionId = @p1',N'@p0 nvarchar(29),@p1 int',@p0=N'Item updated with a
new value',@p1=6

quindi UPDATE NON USA il lenght del mapping

Fabio Maulo

unread,
Mar 4, 2009, 9:05:09 PM3/4/09
to nh...@googlegroups.com
ero convito che funzionasse.. qualcuno havrá messo quel "false" nel dialect per qualche motivo..
e pensare che in NH c'é tutta na storia solo per tipare y parametri.... bah?!??

2009/3/4 makka <Claudio Maccari/> <claudio...@gmail.com>



--
Fabio Maulo

Fabio Maulo

unread,
Mar 15, 2009, 6:34:47 PM3/15/09
to nh...@googlegroups.com
Claudio, visto che giá c'é il post nel blog
puoi, per favore, aggiungere un "How to" wiki qui
e, visto che ci sei, anche un JIRA per rimettere prepare_sql a true di default per MsSQL dialect ?

Grazie.

2009/3/4 Fabio Maulo <fabio...@gmail.com>



--
Fabio Maulo

makka <Claudio Maccari/>

unread,
Mar 16, 2009, 4:18:09 PM3/16/09
to NHibernate-It

Fabio Maulo

unread,
Mar 16, 2009, 4:24:23 PM3/16/09
to nh...@googlegroups.com
2009/3/16 makka <Claudio Maccari/> <claudio...@gmail.com>
Non ti preoccupare che io scrivo in englitagnolo
--
Fabio Maulo

Fabio Maulo

unread,
Mar 25, 2009, 2:23:47 AM3/25/09
to nh...@googlegroups.com
http://nhjira.koah.net/browse/NH-1713

Pare que messo true, come default, causa qualche problema. Lo discutiremo nella dev-list.

2009/3/16 Fabio Maulo <fabio...@gmail.com>



--
Fabio Maulo
Reply all
Reply to author
Forward
0 new messages