Hello
I try to use stored procedure in nhibernate and I found some methods :
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<sql-query name="CO_Visites_Treeview_Sel">
exec CO_Visites_Treeview_Sel :Idclient, :Idmagasin, :Autre, :Tous
</sql-query>
</hibernate-mapping>
If I want to use the data I will use :
var query = session.GetNamedQuery("CO_Visites_Treeview_Sel");
query.SetString("Idclient", lstClients.SelectedValue.ToString());
query.SetInt32("Idmagasin", 36);
query.SetBoolean("Autre", false);
query.SetBoolean("Tous", true);
var results = query.List();
In that case I won't have intellisence neither result['colName']
I use another method :
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernate.DataAccess.Models.Visites_Treeview,NHibernate.DataAccess" lazy="true">
<id name="Idvisite" column="IDVISITE" type="string">
<generator class="assigned" />
</id>
<property column="NOMMAGASIN" name="Nommagasin" type="string" />
<property column="DATEVIS" name="Datevis" type="DateTime" />
<property column="INTERVENTION" name="Intervention" type="Boolean" />
<property column="IDFACTURE" name="Idfacture" type="string" />
<property column="STATUT" name="Statut" type="byte" />
<property column="NOFACTURE" name="Nofacture" type="int" />
<property column="NODEVIS" name="Nodevis" type="int" />
<property column="LIVRE" name="Livre" type="Boolean" />
<property column="NOCOMMANDE" name="Nocommande" type="int" />
<property column="COMPTABILISEE" name="Comptabilisee" type="Boolean" />
<property column="RECUP" name="Recup" type="Boolean" />
<property column="MASQUE" name="Masque" type="Boolean" />
</class>
<sql-query name="CO_Visites_Treeview_Sel">
<return alias="Visites_Treeview" class="NHibernate.DataAccess.Models.Visites_Treeview,NHibernate.DataAccess">
<return-property column="NOMMAGASIN" name="Nommagasin" />
<return-property column="IDVISITE" name="Idvisite" />
<return-property column="DATEVIS" name="Datevis" />
<return-property column="INTERVENTION" name="Intervention" />
<return-property column="IDFACTURE" name="Idfacture" />
<return-property column="STATUT" name="Statut" />
<return-property column="NOFACTURE" name="Nofacture" />
<return-property column="NODEVIS" name="Nodevis" />
<return-property column="LIVRE" name="Livre" />
<return-property column="NOCOMMANDE" name="Nocommande" />
<return-property column="COMPTABILISEE" name="Comptabilisee" />
<return-property column="RECUP" name="Recup" />
<return-property column="MASQUE" name="Masque" />
</return>
exec CO_Visites_Treeview_Sel :Idclient, :Idmagasin, :Autre, :Tous
</sql-query>
</hibernate-mapping>
I created a bean class.
In that case results will have strongly typed object but I have some coherency problem.
But I have no real identifier so if there is two Idvisite, the second will be ignored.
I tryed to create a composite key but it doesn't work.
<composite-id>
<key-property name="Idvisite" column="IDVISITE" type="string" />
<key-property name="Idfacture" column="IDFACTURE" type="string" />
</composite-id>
And I've an error :
could not execute query
[ exec CO_Visites_Treeview_Sel #p0, #p1, #p2, #p3 ]
Name:Idclient - Value:036000004130 Name:Idmagasin - Value:36 Name:Autre - Value:False Name:Tous - Value:True
[SQL: exec CO_Visites_Treeview_Sel #p0, #p1, #p2, #p3]
Can someone tell me how to do ?
Regards
Try this, your mapping:-
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<sql-query name="CO_Visites_Treeview_Sel">
exec CO_Visites_Treeview_Sel :Idclient, :Idmagasin, :Autre, :Tous
</sql-query>
</hibernate-mapping>
use SetResultTransformer...
var results = Session
.GetNamedQuery("CO_Visites_Treeview_Sel")
.SetString("Idclient", lstClients.SelectedValue.ToString())
.SetInt32("Idmagasin", 36)
.SetBoolean("Autre", false)
.SetBoolean("Tous", true)
.SetResultTransformer(new AliasToBeanResultTransformer(typeof(YOURCLASS)));
return results.List<YOURCLASS>();
and YOURCLASS is:-
public class YOURCLASS
{
public virtual int ColA { get; set; }
public virtual string COLB { get; set; }
public virtual int COLC { get; set; }
// etc..
}
HTH
Related
How to work with NHibernate and Oracle using Oracle Sequence?
When I call to the SaveOrUpdate() method, it only performs a select query against the Oracle sequence.
I have used an interceptor to look up the query the session was performing, and the is the instruction I get:
select INFO_ACCESS_REQS_ID_SEQ.nextval from dual;
And that is the only thing being executed against the underlying Oracle database when I call to ISession.SaveOrUpdate().
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="MyProject">
<property name="connection.driver_class">
NHibernate.Driver.OracleClientDriver
</property>
<property name="format_sql">true</property>
<property name="show_sql">true</property>
<property name="dialect">NHibernate.Dialect.Oracle10gDialect</property>
<property name="query.substitutions">
true 1, false 0, yes 'Y', no 'N'
</property>
</session-factory>
</hibernate-configuration>
InformationAccessRequest.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="MyProject.Model"
assembly="MyProject">
<class name="InformationAccessRequest" table="INFO_ACCESS_REQS">
<id name="Id" column="INFO_ACCESS_REQS_ID">
<generator class="native">
<param name="sequence">INFO_ACCESS_REQS_ID_SEQ</param>
</generator>
</id>
<property name="Assembly" column="ASSEMBLY_DT" />
<property name="Requested" column="INFO_ACCESS_REQ_DT" />
<property name="Expiration" column="INFO_ACCESS_REQ_EXP_DT" />
<property name="RequesterIdentification" column="INFO_ACCESS_REQ_USR_ID" />
<property name="Number" column="INFO_ACCESS_REQ_NUM" />
<property name="Reception" column="INFO_ACCESS_REQ_RECEP_DT" />
<property name="Creator" column="CREATOR_ID" />
<property name="Created" column="CREATED_DT" />
<property name="Updater" column="UPDATER_ID" />
<property name="Updated" column="UPDATED_DT" />
<property name="Deleted" column="DELETED_DT" />
</class>
</hibernate-mapping>
ISession.SaveOrUpdate()
var newRequest = new InformationAccessRequest();
newRequest.Requested = DateTime.Today.AddDays(-1);
newRequest.Expiration = DateTime.Today.AddDays(1);
newRequest.Reception = DateTime.Today;
newRequest.Number = Guid.NewGuid().ToString().Substring(0, 12);
newRequest.RequesterIndentification = Guid.NewGuid()..ToString().Substring(0, 10);
newRequest.Created = DateTime.Today;
newRequest.Creator = User.Current.Login;
newRequest.IsNew = true;
newRequest.IsDirty = true;
session.SaveOrUpdate(newRequest);
All required information provided, and all database constraints respected. The SaveOrUpdate() only does the select against the sequence, and no other sql instruction gets performed.
I just discovered a new feature of NHibernate working with identity-type, though it is an old feature actually.
Based on this article: NH2.1.0: New generators, I shall specify the generator class as sequence-identity.
From that new generators article, here's the plain explanation:
sequence-identity
The “sequence-identity” is based on “sequence” but work as an “identity”. The POID values is retrieved with the INSERT query. The types, in your entity, maybe are System.Int32 or System.Int64 depending on your RDBMS sequence generator.
The query that run in ORACLE is:
INSERT INTO my_entity (id, name)
VALUES (hibernate_sequence.nextval, :p0) returning id into :nhIdOutParam
The “hibernate_sequence” is the default name for a sequence where no alternative name is provided trough the mapping. As you can see, in this case, the “sequence” are working like “identity”, the value of the POID is retrieved immediately and the generator has the same problem of “identity”.
InformationAccesRequest.hbm.xml (updated accordingly)
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="MyProject.Model"
assembly="MyProject">
<class name="InformationAccessRequest" table="INFO_ACCESS_REQS">
<id name="Id" column="INFO_ACCESS_REQS_ID">
<generator class="sequence-identity">
<param name="sequence">INFO_ACCESS_REQS_ID_SEQ</param>
</generator>
</id>
<property name="Assembly" column="ASSEMBLY_DT" />
<property name="Requested" column="INFO_ACCESS_REQ_DT" />
<property name="Expiration" column="INFO_ACCESS_REQ_EXP_DT" />
<property name="RequesterIdentification" column="INFO_ACCESS_REQ_USR_ID" />
<property name="Number" column="INFO_ACCESS_REQ_NUM" />
<property name="Reception" column="INFO_ACCESS_REQ_RECEP_DT" />
<property name="Creator" column="CREATOR_ID" />
<property name="Created" column="CREATED_DT" />
<property name="Updater" column="UPDATER_ID" />
<property name="Updated" column="UPDATED_DT" />
<property name="Deleted" column="DELETED_DT" />
</class>
</hibernate-mapping>
I have a problem with shared column between composite id and multi column many to one relation in large legacy database. I have simplified the problem into mapping below which reproduce the problem:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Alfa">
<composite-id name="AlfaId" class="AlfaCompositeId">
<key-many-to-one name="Bravo" class="Bravo" column="BRAVO_ID" />
<key-property name="CharlieId1" column="CHARLIE_ID1" />
</composite-id>
<many-to-one name="C" class="Charlie">
<column name="CHARLIE_ID1" />
<column name="BRAVO_ID" />
</many-to-one>
<property name="CookieA" column="COOKIE_A" />
</class>
<class name="Bravo">
<id name="BravoId" column="BRAVO_ID" />
<property name="CookieB" column="COOKIE_B" />
</class>
<class name="Charlie">
<composite-id>
<key-property name="CharlieId1" column="CHARLIE_ID1" />
<key-many-to-one name="Bravo" class="Bravo" column="BRAVO_ID" /> <!-- Reused column !!! -->
</composite-id>
<property name="CookieC" />
</class>
</hibernate-mapping>
Trying to save Alfa entity will throw:
IndexOutOfRangeException (Message=Invalid index 3 for this SqlParameterCollection with Count=3).
NHibernate is trying to add BRAVO_ID column value twice. Once for composite id and once for many to one FK.
Any way how to change to mapping XML to tell NHibernate to ignore second mapping of 'BRAVO_ID' column?
Any tips appreciated.
you mapped the same columns as CompositeId and as ManyToOne, just get rid of the compositeId
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Alfa">
<composite-id>
<key-many-to-one name="Charly" class="Charlie">
<column name="CHARLIE_ID1" />
<column name="BRAVO_ID" />
</key-many-to-one>
</composite-id>
<property name="CookieA" column="COOKIE_A" />
</class>
<class name="Bravo">
<id name="Id" column="BRAVO_ID" />
<property name="CookieB" column="COOKIE_B" />
</class>
<class name="Charlie">
<composite-id>
<key-property name="IdPart1" column="CHARLIE_ID1" />
<key-many-to-one name="Bravo" class="Bravo" column="BRAVO_ID" />
</composite-id>
<property name="CookieC" />
</class>
</hibernate-mapping>
and Access it through the Property
Bavo b = alfa.Charly.Bravo;
This is my mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel">
<class name="Cliente" table="Clientes">
<id name="Id" column="ID" type="guid" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb" />
</id>
<property name="Nombre" column="Nombre" not-null="true" type="string" length="50" />
<property name="Direccion" column="Direccion" not-null="false" type="string" length="75" />
<property name="Telefono" column="Telefono" not-null="false" type="string" length="15" />
<property name="Email" column="Email" not-null="false" type="string" length="50" />
<property name="FechaAlta" column="FAlta" not-null="true" type="DateTime" />
<list name="Pedidos" cascade="all-delete-orphan">
<key column="Cliente"/>
<index column="FechaEntrada"/>
<one-to-many class="Pedido"/>
</list>
</class>
</hibernate-mapping>
When I try to insert a new "Cliente" (Customer) into the database, NHibernate generates instead an UPDATE command, looking to update the customer with ID 00000000-0000-0000-0000-000000000000. As it doesn't exist, I naturally get the exception:
InnerException: NHibernate.StaleStateException
Message="Unexpected row count: 0; expected: 1"
I'm guessing this has to be a noob NHibernate error, but I've been checking my mapping with other guid example mappings on the web and I don't see my mistake.
Thanks!
PS.- As requested, this is the code I use to do the insertion:
// METHOD 1
//BusinessTransaction bt = new BusinessTransaction(sesion);
//bt.Attach(cliente);
//bt.Commit();
//bt.Close();
// METHOD 2
ITransaction trans = sesion.BeginTransaction();
sesion.SaveOrUpdate(cliente);
trans.Commit();
sesion.Flush();
sesion is an ISession object created with the BuildSessionFactory method of NHibernate Configuration. Method 1 provokes the error described, an UPDATE when it should be doing an INSERT, while Method 2 works, however (I'm an idiot and was looking a the wrong database file).
PPS.- For the sake of testing I've changed the guid fields for auto-incremented int identity fields, but my problems are the same.
PPPS.- Just in case, this are the contents of my hibernate.cfg.xml file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSqlCeDialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlServerCeDriver</property>
<property name="connection.connection_string">Data Source=Pedidos.sdf</property>
<property name="show_sql">true</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<mapping assembly="PedidosDomainModel" />
</session-factory>
</hibernate-configuration>
Here's one solution: Map the Id (that's how I map it in Fluent, you will sort out an equivalent in XML mapping)
Id(x => x.Id).GeneratedBy.Assigned();
And before saving you can do something like this:
if (client.HasEmptyId())
{
client.Id = Guid.NewGuid();
session.Save(client);
}
else
{
session.Update(client);
}
In my program, i need get a exec a store procedure to decide to get a object from which table, so i need config a stored procedure in my entity nhibernate config file, the config file like below:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Entity.ACC.User, Entity" table="ACC_User" lazy="false">
<id name="Id" column="Id" type="Int32" unsaved-value="0" >
<generator class="increment" />
</id>
<property name="Code" column="Code" type="String" length="50" />
<property name="Password" column="Password" type="String" length="50" />
<property name="FirstName" column="FirstName" type="String" length="50" />
<property name="LastName" column="LastName" type="String" length="50" />
<property name="Type" column="Type" type="Int16" />
<property name="Email" column="Email" type="String" length="50" />
<property name="TelPhone" column="TelPhone" type="String" length="50" />
<property name="MobilePhone" column="MobilePhone" type="String" length="50" />
<property name="Language" column="Language" type="String" length="50" />
<property name="IsActive" column="IsActive" type="Boolean" />
<property name="AccountExpired" column="AccountExpired" type="Boolean" />
<property name="AccountLocked" column="AccountLocked" type="Boolean" />
<property name="PasswordExpired" column="PasswordExpired" type="Boolean" />
<property name="CreateUserId" column="CreateUser" type="Int32" update="false" />
<property name="CreateUserName" column="CreateUserNm" type="String" length="100" update="false" />
<property name="CreateDate" column="CreateDate" type="DateTime" update="false" />
<property name="LastModifyUserId" column="LastModifyUser" type="Int32" />
<property name="LastModifyUserName" column="LastModifyUserNm" type="String" length="100" />
<property name="LastModifyDate" column="LastModifyDate" type="DateTime" />
<sql-insert>
exec USP_User_Insert ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?
</sql-insert>
<sql-update>
exec USP_User_Update ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?
</sql-update>
<sql-delete>
exec USP_User_Delete ?
</sql-delete>
</class>
<sql-query name="User_Select">
<return class="Entity.ACC,Entity.ACC.User"/>
exec USP_User_Select ?
</sql-query>
</hibernate-mapping>
after i added this query SP in the config file
exec USP_User_Select ?
the program can't run and will throw exception as:
unknown class Entity.ACC, Entity.ACC.User
what should i do let the SP work.
many thanks.
Try changing
return class="Entity.ACC,Entity.ACC.User"
line into
return class="Entity.ACC.User, Entity"
I have the following mapping files:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MyAssembly" namespace="EntityNamespace">
<class name="Server" xmlns="urn:nhibernate-mapping-2.2" table="tblServer" >
<id name="Id" type="int">
<generator class="native" />
</id>
<bag name="Services" cascade="all" inverse="true" lazy="true">
<key column="Id" />
<one-to-many class="Service" />
<filter name="currentServices" condition=":currentDate BETWEEN DtStart AND DtEnd" />
</bag>
</class>
<filter-def name="currentServices">
<filter-param name="currentDate" type="System.DateTime"/>
</filter-def>
</hibernate-mapping>
and:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyAssembly" namespace="EntityNamespace">
<class name="Service" xmlns="urn:nhibernate-mapping-2.2" table="tblService" >
<id name="Id" type="int">
<generator class="native" />
</id>
<many-to-one name="Server" column="server_id" />
<join table="tblServiceOptMatrix">
<key column="ServiceOptID" />
<property name="StartDate" column="DtStart" type="DateTime" />
<property name="EndDate" column="DtEnd" type="DateTime" />
</join>
</class>
</hibernate-mapping>
and the following criteria API:
IList<Server> servers;
using (var tx = Session.BeginTransaction())
{
Session.EnableFilter("currentServices")
.SetParameter("currentDate", DateTime.Now);
servers = Session.CreateCriteria<Server>()
.List<Server>();
tx.Commit();
}
and the sql that is generated for lazily retrieving services looks like this:
SELECT service0_.server_id as server2_1_,
service0_.id as id1_,
service0_1_.DtStart as DtStart256_0_,
service0_1_.DtEnd as DtEnd256_0_
FROM tblTfopt valueadded0_
inner join tblServiceOptMatrix service0_1_
on service0_.id = service0_1_.ServiceOptID
WHERE '2010-01-07T14:58:09.00' /* #p0 */
BETWEEN service0_.DtStart AND service0_.DtEnd
and service0_.server_id = 993 /* #p1 */
where the server id and date are examples. The problem is that the sql produced for the filter is using the wrong table alias, It should instead be this:
BETWEEN service0_1_.DtStart AND service0_1_.DtEnd
What am I doing wrong? Is there a better way to do this?