Named Query and Inheritance - c#

I'm having some issues when running a named query on NHibernate. The class I'm setting as the return value is Organization - not abstract -, and I have a second class (which inherits from this one) called FullOrganization. I have a table per concrete class schema and everything else is working just fine, but I keep getting an exception when running the named query (which BTW doesn't provide any details).
The mapping is close to the following:
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
namespace="XXX"
assembly="XXX"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:nhibernate-mapping-2.2 ..\nhibernate-mapping.xsd" auto-import="false">
<class name="Organization" table="Organizations" lazy="false">
<id name="Identity" column="Id">
<generator class="identity"/>
</id>
<property name="Name" column="Name" />
<many-to-one name="OrganizationType" column="OrganizationTypeId"/>
...
<joined-subclass name="FullOrganization" table="FullOrganizations" lazy="false">
<key column="OrganizationId"/>
...
</joined-subclass>
</class>
And the named query goes something like:
<sql-query name="OrganizationSearch" read-only="true" cacheable="false">
<return class="Organization" />
<![CDATA[
SELECT *
FROM Organizations o
INNER JOIN OrganizationTypes ot ON o.OrganizationTypeId = ot.Id
LEFT JOIN FullOrganizations fo ON o.Id = fo.OrganizationId
WHERE
// Several Filters Here
]]>
How should I map the query results? Please take into account that returned objects could be instances of Organization or FullOrganization.

If I am understanding the question correctly, do you have two methods for the search? i.e.
SearchOrganisations and SearchFullOrganisations
If answer is yes then I would remove the
<return class="Organization" />
and in code you can use the AliasToBeanResultTransformer
so one method
return Session
.GetNamedQuery("OrganizationSearch")
.SetString("Param1", param1)
.SetResultTransformer(new AliasToBeanResultTransformer(typeof(Organization )))
.List<Organization >();
and also
return Session
.GetNamedQuery("OrganizationSearch")
.SetString("Param1", param1)
.SetResultTransformer(new AliasToBeanResultTransformer(typeof(FullOrganization )))
.List<FullOrganization >();
If you have one method then you can set a switch to apply the desired SetResultTransformer

Related

Nhibernate: return results that join on the same table

I've got what I think is a simple query but cannot for the life of me figure out how to do this using nhibernate 2.X.
Suppose I have this simple SQL Query that joins on the same table, how can I return a list of objects?
select primary_details.*,
secondary_details.*,
from details primary_details
JOIN details secondary_details
ON primary_details.ID = secondary_details.ID;
Now obviously there is other criteria that would be applied so I don't get a result set of the same data duplicated, but I've simplified it for my question.
My details Domain and mappings work fine if I just do a Select from details, but what I need is a result set with the data joined so I can chart a column from primary_details against secondary_details.
Any ideas would be appreciated. Even if it the solution is to handle this outside of nhibernate somehow.
Dumbed down Mapping File:
<class name="details" table="details" lazy="true" schema-
action="none">
<id name="ID">
<column name="ID" sql-type="varchar(32)" />
</id>
<property name="Name">
<column name="Name" not-null="false" />
</property>
<property name="Value">
<column name="laboratory_id" not-null="false" />
</property>
</class>
Cheers
Try this:
var session.CreateSQLQuery("select {pd.*}, {sd.*}, from details pd JOIN details sd ON pd.ID = sd.ID").AddEntity("sd", typeof(details)).AddEntity("pd", typeof(details)).List<details>();

NHibernate Envers - how to audit revisions on a separate database?

I'm using Nhibernate Envers and I want Envers to save audit info on a separate database to keep things cleaner/more maintainable.
I'm using this fluent configuration:
var enversCfg = new NHibernate.Envers.Configuration.Fluent.FluentConfiguration()
enversCfg.Audit(GetDomainEntities())
nhCfg.SetEnversProperty(ConfigurationKey.DefaultCatalog, "nhibernate_testAU")
but when I try to create the schema, I get a HibernateException (The specified schema name "nhibernate_testAU" either does not exist or you do not have permission to use it.)
for what it's worth, my backend is SQL Server 2005
In addition to actually creating the database, I specified the schema to "dbo".
c.SetEnversProperty(ConfigurationKey.DefaultSchema, "dbo");
c.SetEnversProperty(ConfigurationKey.DefaultCatalog, "MyCatalog_Audit");
Also, I have my own RevistionEntity class, so, I needed to add the catalog and schema to my hbm.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyAssembly" namespace="MyNamespace">
<class name="MyRevisionEntity" table="REVINFO" catalog="MyCatalog_Audit" schema="dbo">
<id name="Id" column="MyRevisionEntityId">
<generator class="identity"/>
</id>
<property name="AuditDate"></property>
<property name="UserName"></property>
<!--modifiedEntityNames-->
<set name="ModifiedEntityNames" table="REVCHANGES" catalog="MyCatalog_Audit" schema="dbo">
<key column="REV"/>
<element column="ENTITYNAME" type="string"/>
</set>
</class>
</hibernate-mapping>
HTH
Chuck
You need to manually create the catalog/database. AFAIK - NH's SchemaExport don't create database/catalog (or schemas) for you.

Need help with simple NHibernate mapping

Need help with a simple NHibernate relationship...
Tables/Classes
Request
-------
RequestId
Title
…
Keywords
-------
RequestID (key)
Keyword (key)
Request mapping file
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="CR.Model" assembly="CR">
<class name="CR.Model.Request, CR table="[dbo].[Request]" lazy="true">
<id name="Id" column="[RequestID]">
<generator class="native" />
</id>
<property name="RequestorID" column="[RequestorID]" />
<property name="RequestorOther" column="[RequestorOther]" />
…
Keyword??
</class>
</hibernate-mapping>
How do I simply map multiple keywords to a request? I don't need another mapping file for the keyword class, do I?
It's be great if I could not only get the associated keywords, but add them too...
You'll need a set (or some other kind of collection mapping, but I think a set is the best-fit).
check this

NHibernate: Is it possible to use stored proc when updating/deleting/inserting a class mapped on view?

Here is the preamble:
I have a SQL View and mapped NHibernate C# class
I only allowed to modify SQL View data through some stored procedures (Insert/Update/Delete)
How to denote such logic in mapping file? Is it possible with only specific mapping or i need some supplementary code?
This is described in 19.3. Custom SQL for create, update and delete
Example:
<class name="Person" table="PersonView">
<id name="id">
<generator class="guid"/>
</id>
<property name="name" not-null="true"/>
<sql-insert>exec createPerson ?, ?</sql-insert>
<sql-delete>exec deletePerson ?</sql-delete>
<sql-update>exec updatePerson ?, ?</sql-update>
</class>
You could invoke your SQL's stored procedures using NHibernate's Named Queries:
< ?xml version="1.0" encoding="utf-8"?>
<hibernate -mapping xmlns="urn:nhibernate-mapping-2.2">
<sql -query name="FindPlayerByLastDrugTest">
<query -param name="LastDrugTestDate" />
<return class="Player">
<return -property column="PlayerID" name="PlayerID" />
<return -property column="PlayerName" name="Name" />
<return -property column="TeamID" name="Team" />
<return -property column="LastDrugTestID" name="LastDrugTestResult" />
</return>
exec spSelectPlayersByLastDrugTestDate #LastDrugTest=:LastDrugTestDate
</sql>
</hibernate>
/*** Back on C# ***/
IQuery query = session.GetNamedQuery("FindPlayerByLastDrugTest")
.SetDateTime(new DateTime(2003, 1, 1));
// Return a collection
IList list = query.List();
// Return a single entity
var result = query.UniqueResult();
More information here.

Stack Overflow whilst cascade saving nhibernate entity with custom generator

I'm pretty new to Nhibernate, so apologies for a long - winded description
I suspect that changing the structure of the legacy DB is probably the best option, but I want to try and get NHibernate to deal with it.
Basically the structure is this an EndPoint has an address and a contact. Endpoint is stored in a table with a composite ID (Address ID, Contact ID).
I'm having a problem when cascade saving an address, which has a custom ID generator - address ID are of the form "ADR000234" to fit in with a legacy DB structure.
The custom ID generator includes a query, and when I save the address as part of an endpoint, I get a stack overflow. When debugging the cursor gets to line that evaluates the query( var maxAddressID..), then jumps back to start of the method, and keeps on doing this until it raises a stack overflow.
Here's my generator class
public class AddressIdGenerator : IIdentifierGenerator
{
public object Generate(ISessionImplementor session, object obj)
{
var castAsSession = (ISession)session;
var allAddresses = castAsSession.CreateQuery("select max(Code) from Address a");
var maxAddressID = (string)allAddresses.List()[0];
var previousNumber = int.Parse(maxAddressID.Substring(3, 6));
return GetNewId("ADR", previousNumber);
}
private string GetNewId(string prefix, int number)
{
return prefix + (number + 1).ToString().PadLeft(6, '0');
}
}
Here's my mapping foe the EndPoint CLass
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="DataClasses"
namespace="DataClasses">
<class name="EndPoint" table="[Addresses_Contacts]">
<composite-id>
<key-property name ="Address" column ="[Address ID]" type="string" />
<key-property name ="Contact" column ="[Contact ID]" type="string"/>
</composite-id>
<many-to-one name="Address" class="DataClasses.Address, DataClasses" cascade="save-update"/>
<many-to-one name="Contact" class="DataClasses.Contact, DataClasses" cascade="save-update"/>
</class>
</hibernate-mapping>
and the mapping for address:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DataClasses" namespace="DataClasses">
<class name="Address" table="[Lookup Addresses]" >
<id name="Code" column="ID" type="string">
<generator class="Nhibernate.AddressIdGenerator, Nhibernate" />
</id>
<property name="OrganisationName" column="[Name of Organisation]"/>
<property name="StreetAddress1" column="[Park/centre/estate]" />
<property name="StreetAddress2" column="[Street Name]" />
<property name="Town" column="[Town/City]" />
<property name="State" column="[Region/ State]" />
<property name="PostCode" column="[Postal/ Area Code]" />
<property name="District" column="[Local District]" />
<property name="Airport" column="[Airport code]" />
<many-to-one name="Country" class="DataClasses.Country, DataClasses" column ="[Country Code]"/>
</class>
</hibernate-mapping>
If I try to save and Address on its own, it works fine, the ID is generated with no problems.
Also if I remove the Address and Contact properties from the mapping (but not from the composite ID), and save the Address and Contact before saving the Endpoint, it's fine too.
It seems to me that when I'm doing the cascade save, for some reason it can't run other queries during the process, but rather than throwing an exception it's behaving strangely (restarting the method again and again). I haven't ever seen a C# method do this before. I'd love to know if anyone has an idea of how to fix this.
i'm thinking that the problem resides that you are doing an nh-query inside the Generator and you are querying the entity type you want to save.
The generator is called not when you call Save() but whenever there is a need to flush/commit the data. Now, Save() places the entity on a action-queue of things to do. When you call CreateQuery/CreateCriteria and request the result via List()/UniqueResult() nhibernate's engine detects that you made a Save() request on an entity and so will try to flush/commit the entity first (and thus call the generator) and then perform the query and thus start an infinite loop; The logic is such that since you called Save() and then you are querying that class type you will want the result set to include the Saved object.
So, replace your Nh-query with a native SqlCommand (there is a possibility CreateSqlQuery will work too) and i think your problem will be solved.
please update the owner of the relation in the EndPoint xml Mapping.
please mention inverse="true"in the many to one proper for address and contacts.
thanks

Categories

Resources