I am trying to retrieve the count of items allocated to a container in my hbm file. I've done a bit of digging and managed to get my hbm code this far (below!). I want the count to be retrieved every time a container object is queried. I could use an interceptor but I assume there's a better way. Am I on the right track or should I use a different strategy to get the count loaded up?
Thanks.
P.S. We're using NH v2.2
<?xml version="1.0" encoding="utf-8"?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false" assembly="MyEntities" namespace="Entities.Containers"> <class name="Container" table="[Container]" xmlns="urn:nhibernate-mapping-2.2">
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<property name="Capacity" column="Capacity">
<column name="Capacity" />
</property>
<property name="Description" column="Description" length="50" type="String">
<column name="Description" />
</property>
<loader query-ref="sqCurrentContainerAllocation"/> </class>
<sql-query name="sqCurrentContainerAllocation">
<return-scalar column="AllocatedItemsCount" type="int"></return-scalar>
SELECT COUNT(*) FROM [ContainerTracking]
WHERE [ContainerId] = :Id </sql-query>
</hibernate-mapping>
If you need to get some calculated property, you can use mapping with formula.
Let's extend your C# class:
public class Container
{
... // ID, Capacity, Description
public virtual int MyCount { get; set; }
And extend your mapping
<class name="Container" table="[Container]"
...
<property name="MyCount" insert="false" update="false" >
<formula>
(
SELECT count(*)
FROM [ContainerTracking] as ct
WHERE ct.[ContainerId] = Id
)
</formula>
</property>
the Id will be replaced with somethink like '_this.Id', the name of the column Id and its alias
This will of course load the count all the time (except projections) so think twice before use it
Related
Forgive me I am a newbie in NHibernate, I found some example in hbm.xml like below.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="test" >
<class name="test.FieldSetMapping" table="fieldsetmapping" discriminator-value="2352" lazy="false">
<id name="Id" column="fieldsetmapping_id" type="Int64">
<generator class="test.NHibernate.IdGenerator, test">
<param name="table">nextinstanceid</param>
<param name="column">next</param>
<param name="max_lo">9</param>
</generator>
</id>
<discriminator column="mapping_type" type="Int32" />
<version name="LastUpdateNumber" column="last_update_number" type="Int32" unsaved-value="-1"/>
<property name="OwnerName" column= "owner_name" type="String"/>
<component name="FieldSetDefinitionId" class="test.ObjectId">
<property name="InstanceId" column= "fieldsetdefinition_id" type="Int64"/>
</component>
<property name="OwnerTypeClassId" column= "owner_type" />
<bag name="FieldMappings" cascade="all-delete-orphan" generic="true" lazy="false">
<key column="fieldsetmapping_id" not-null="true" />
<one-to-many class="test.FieldSet.FieldMapping, test" />
</bag>
<property name="MappingHandlerClass" column="handler_class" />
</class>
<subclass name="test.EntityFieldSetMapping, test" discriminator-value="2353" extends="test.FieldSetMapping, test" lazy="false" >
<property name="TargetEntityType" type="test.Internal.NHibernate.ClassIdType, test" not-null="false">
<column name="target_entity_type"/>
</property>
</subclass>
<class ...>
...
</class>
<class ...>
...
</class>
</hibernate-mapping>
But I don't know what does discriminator mean . I check the Nhibernate Doc 5.1.6.
The <discriminator> element is required for polymorphic persistence
using the table-per-class-hierarchy mapping strategy and declares a discriminator
column of the table. The discriminator column contains marker values that tell
the persistence layer what subclass to instantiate for a particular row.A restricted
set of types may be used: String, Char, Int32, Byte, Short, Boolean, YesNo, TrueFalse.
Does it mean if the mapping_type > 2352 the NH will initialize the subclass test.EntityFieldSetMapping for the row of the table fieldsetmapping? thanks.
NHibernate will use the discriminator to detect which class needs to instantiate on a polymorphic scenario.
If mapping_type = 2352, it will create an instance of test.FieldSetMapping
if mapping_type = 2353, it will create an instance of test.EntityFieldSetMapping
Any other value should generate an exception.
I've seen a number of examples of this, and as far as I can tell my HBM file follows the same pattern, but it's not working. First, the file:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
<class name="ThinAir" mutable="false" lazy="true" >
<id name="JobId">
<generator class="native" />
</id>
<property name="UserLogin"/>
<property name="UserEmail"/>
<property name="DateProcessed"/>
<loader query-ref="myquery"/>
</class>
<sql-query name="myquery">
<return class="ThinAir">
<return-property name="JobID" column="JobId"/>
<return-property name="userLogin" column="UserLogin"/>
<return-property name="DateProcessed" column="DateProcessed"/>
<return-property name="userEmail" column="UserEmail"/>
</return>
<![CDATA[
SELECT DISTINCT JobID,
userLogin,
DateProcessed,
useremail
FROM dbo.someothertable
]]>
</sql-query>
</hibernate-mapping>
"myquery" in-and-of-itself, works. That is to say, if I call
var x = session.GetNamedQuery("myquery").List();
I get a correct List of ThinAir objects.
But, when I try to get a list of ThinAirs like this:
var submissions = session.CreateCriteria<ThinAir>().List<ThinAir>();
I get
Test method testThinAir threw exception:
NHibernate.Exceptions.GenericADOException: could not execute query
[ SELECT this_.JobId as JobId16_0_, this_.UserLogin as UserLogin16_0_, this_.UserEmail as UserEmail16_0_, this_.DateProcessed as DateProc4_16_0_ FROM ThinAir this_ ]
My interpretation of this phenomenon is that NH is ignoring my <loader> tag and so trying to load the data from the underlying table, which by default it assumes to be named ThinAir because that's the name of the entity class, only there isn't any ThinAir table, hence the error message.
Is that interpretation correct? And in any case, what am I doing wrong and how can I do it right?
Thanks in advance.
Michael
One way how to achieve this, would be to move the mapping from a query into the subselect:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
<class name="ThinAir" mutable="false" lazy="true" >
<subselect>
<![CDATA[
SELECT DISTINCT JobID,
userLogin,
DateProcessed,
useremail
FROM dbo.someothertable
]]>
</subselect>
... // rest of the mapping
I need a HQL Query but I just dont get it.
SELECT * FROM Poll WHERE pid NOT IN (
SELECT pid FROM votes WHERE uid = 'theuserid')
I want all List of PollĀ“s back where the uid not in the table votes exists.
Also helpfull would be the hql query where the uid in the table votes exists, but I guess this is very similar ;-)
These are the 2 classes:
public class Poll {
private int pid;
private String name;
private String description;
private Date deadline;
private Set<Team> teams = new HashSet<Team>(0);
//some getter & setter
}
public class Vote {
private int vid;
private String uid;
private int pid;
private int tid;
private int votes;
//some getter & setter
}
Can smbdy please help me. I guess it is a join with a WHERE and NOT LIKE but I just dont get it.
Merci!
This is btw the hibernate mapping:
<hibernate-mapping>
<class name="package.model.Poll" table="poll">
<id name="pid" column="pid" >
<generator class="increment"/>
</id>
<property name="name" column="name" />
<property name="description" column="description" />
<property name="deadline" type="timestamp" column="deadline" />
<set name="teams" table="pollchoice"
inverse="false" lazy="false" fetch="select" cascade="all" >
<key>
<column name="pid" not-null="true" />
</key>
<many-to-many entity-name="knt.exceedvote.model.Team">
<column name="tid" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="package.model.Vote" table="votes">
<id name="vid" column="vid" >
<generator class="increment"/>
</id>
<property name="pid" column="pid" />
<property name="uid" column="uid" />
<property name="tid" column="tid" />
<property name="votes" column="votes" />
</class>
</hibernate-mapping>
Please keep in mind, Hibernate is designed using the notion of Object Graph, which is a name given to the relational objects.
That core concept is missing in your mapping (Poll and Vote seem to be isolated) hence I doubt you can use HQL in its current state.
In my opinion, you have two options:
Define the relationship between Poll, pid and Vote, uid. Then you should be able to write simple HQL.
Use native SQL through Hibernate session itself.
I am working on a legacy database which is quite intricate.
The table customers is shared with the suppliers and who created this structure used a flag to identify the customers.
Since I am only interested in working with records defined as customers I've added a where clause to my mapping:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyAssembly" namespace="MyAssembly.Domain">
<class name="Customer" table="ANSADID" mutable="false" where="ANFCLI = 'Y'">
<composite-id>
<key-property name="CustomerCode" column="ANCOCO" type="String" length="10"></key-property>
<key-property name="Company" column="ANCOSO" type ="String" length="5"></key-property>
</composite-id>
<property name="Name" column="ANINCO" type="String" length="100"></property>
</class>
</hibernate-mapping>
As you can see I've pre-filtered all my customers with this clause: ANFCLI = 'Y'
Everything works perfectly fine if I query customers (the where clause is used):
var customers = session.QueryOver<Domain.Customer>()
.Where(t => t.Company == "ABC01")
.List();
But if I query the orders table - where I've got a many-to-one association:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyAssembly" namespace="MyAssembly.Domain">
<class name="Order" table="OCSAORH" mutable="false" where="OCHAMND = 0">
<composite-id>
<key-property name="Number" column="OCHORDN" type="String" length="10"></key-property>
<key-property name="Ver" column="OCHAMND" type="Int32"></key-property>
<key-property name="Company" column="OCHCOSC" type="String" length="5"></key-property>
</composite-id>
<many-to-one name="Customer" class="Customer" lazy="proxy" fetch="join">
<column name="OCHCLII" not-null="true"/>
<column name="OCHCOSC" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>
the filter on the entity customers is lost.
I was reading somewhere that the where clause doesn't work on a association and you have to use a where clause on the collection (bag, set, etc etc) but, how can I do that with a many-to-one?
Thanks for you help.
What about mapping Customer using a discriminator using ANFCLI and then setting the discriminator value to 'Y'. I think NHibernate will treat this a little more rigourously than a where clause.
<class name="Customer" table="ANSADID" mutable="false" discriminator-value="Y">
<composite-id>
<key-property name="CustomerCode" column="ANCOCO" type="String" length="10" />
<key-property name="Company" column="ANCOSO" type ="String" length="5" />
</composite-id>
<discriminator column="ANFCLI" />
<property name="Name" column="ANINCO" type="String" length="100" />
</class>
I think degorolls is right:
You would need to have a super class called "Person", and two sub types called "Customer" and "Supplier".
Then you set your mapping so it uses the ANFCLI field as a discriminator, with the Y value for Customer and the N value for Supplier.
This way, you'll have a nice and transparent polymorphism.
(you'll be able to do stuff like "from Customer", or "from Supplier", and that will automagicaly add the where clause).
Hope that helps!
I'm also a newbie using NHibernate but perhaps you can map that relation (Order to Customer) using a bag (as if it would be one to many)!
I've an issue using one-to-one mapping. I've searched internet and found many solutions but none was satisfying. Most of the examples carry overhead of storing parent instance in child class.
I want to use only parent Id in child class having foreign key constraint relationship but dont want to keep any parent instance in child.
When I try to load the records from database it throws exception "No row with the given identifier exists [AssemblyName.]". But, the record exists in Table "B" properly.
Any solutions for this issue?
The class structure:
class A {
public virtual string Id {get;set;}
public virtual B B {get;set;} // properties...... }
class B { public virtual string Id {get;set;} // properties......
public virtual string ParentId { get;set;} // class A Id }
The database structure:
CREATE TABLE [A](
[Id] [nvarchar](45) PRIMARY KEY
) ON [PRIMARY]
CREATE TABLE [B](
[Id] [nvarchar](45) PRIMARY KEY,
[ParentId] [nvarchar](45) NOT NULL
) ON [PRIMARY]
The mapping:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="A,AssemblyName" table="A" lazy="true">
<id name="Id" column="Id" type="string">
<generator class="assigned"/>
</id>
<one-to-one name="_B" cascade="all" fetch="join" foreign-key="None" constrained="true" class="B"/>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="B,AssemblyName" table="B" lazy="true">
<id name="Id" column="Id" type="string"> <generator class="assigned"/> </id>
<property name="_Name" column="Name"/> </class>
</hibernate-mapping>
One-to-one associations are always bidirectional in NHibernate. Mapping of class B is incomplete:
<class name="B,AssemblyName" table="B" lazy="true">
<id name="Id" column="Id" type="string">
<generator class="assigned"/>
</id>
<many-to-one name="A" unique="true" column="A" />
<property name="_Name" column="Name"/>
</class>
This is foreign key association. For more information see this detailed Ayende's blog post or NHibernate documentation.
Read this. A "real" one-to-one needs the same primary key in both tables (and no ParentId column).