I have two tables: run_info and inventory. run_info has a column fk_pss which is a unique, not null reference to the primary key in inventory. Looking at the nHibernate documentation (
http://www.hibernate.org/hib_docs/nhibernate/html_single/#mapping-declaration-onetoone) I discovered that one-to-one relationships with unique, not null foreign keys must be expressed as a many-to-one relationship. Following a very similar format to the example I get the results I want.
Unfortunately, immediately after the results are returned, nHibernate makes another database hit asking for some of the same data again (see query two below), supplying 1 for fk_pss (I have no idea where it gets this number) and ultimately crashing since there is no inventory row which contains that primarykey. It's as if there's a lazy load on the many-to-one strategy which obviously isn't possible.
It's irritating because I can see that all the information that I need is being asked for (query one), but somewhere in the mapping everything is falling apart. The exception is an UnresolvableObjectException which appears to be thrown if something is null, but as far as I know the results don't contain any null values. After spending two days rifling through nHibernate's documentation and searching the forum I feel that I've performed due diligence before posting.
Hibernate version:
nHibernate-1.0.1.0
Mapping documents:
RunInfo.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" assembly="Monitor" namespace="Dcp.Monitor.Model">
<class name="RunInfo" table="run_info">
<id name="Id" column="index" type="Int32">
<generator class="sequence">
<param name="sequence">run_info_index_seq</param>
</generator>
</id>
<bag name="ShiftFragments" lazy="true">
<key column="fk_run"/>
<one-to-many class="ShiftFragment"/>
</bag>
<many-to-one name="Pss" class="InventoryItem" column="fk_pss" unique="true"/>
<property name="StartTime" column="start_time" type="DateTime"/>
<property name="EndTime" column="end_time" type="DateTime"/>
</class>
</hibernate-mapping>
Inventory.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" assembly="Monitor" namespace="Dcp.Monitor.Model">
<class name="InventoryItem" table="inventory">
<id name="Id" column="index" type="Int32">
<generator class="sequence">
<param name="sequence">inventory_index_seq</param>
</generator>
</id>
<property name="PartCode" column="part_code" type="String"/>
<property name="QuantityOnHand" column="quantity_on_hand" type="Int32"/>
<property name="Unit" column="unit" type="String"/>
<property name="Description" column="description" type="String"/>
<property name="Cost" column="cost" type="Decimal"/>
<property name="SellPrice" column="sell_price" type="Decimal"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
ICriteria criteria = Session.CreateCriteria(typeof(RunInfo));
ICriterion c1 = new GeExpression("StartTime", startTime);
ICriterion c2 = new LeExpression("EndTime", endTime);
criteria.Add(new AndExpression(c1, c2));
return criteria.List();
Full stack trace of any exception that occurs:Full stack trace
Code:
at NHibernate.UnresolvableObjectException.ThrowIfNull(Object o, Object id, Type clazz)
at NHibernate.Impl.SessionImpl.InternalLoad(Type clazz, Object id)
at NHibernate.Type.ManyToOneType.ResolveIdentifier(Object id, ISessionImplementor session)
at NHibernate.Type.EntityType.ResolveIdentifier(Object id, ISessionImplementor session, Object owner)
at NHibernate.Impl.SessionImpl.InitializeEntity(Object obj)
at NHibernate.Loader.Loader.InitializeEntitiesAndCollections(IList hydratedObjects, Object resultSetId, ISessionImplementor session)
at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Object optionalObject, Object optionalId, Object[] optionalCollectionKeys, Boolean returnProxies)
at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Object optionalObject, Object optionalId, Object[] optionalCollectionKeys, Boolean returnProxies)
at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet querySpaces, IType[] resultTypes)
at NHibernate.Loader.CriteriaLoader.List(ISessionImplementor session)
at NHibernate.Impl.SessionImpl.Find(CriteriaImpl criteria)
at NHibernate.Impl.CriteriaImpl.List()
at Dcp.Monitor.Data.RunInfoDao.SelectByDateTimeRange(DateTime startTime, DateTime endTime, ICriteria criteria) in C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\Data\RunInfoDao.cs:line 88
at Dcp.Monitor.Data.RunInfoDao.SelectByDateTimeRange(DateTime startTime, DateTime endTime) in C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\Data\RunInfoDao.cs:line 51
at Dcp.Monitor.Controller.ProductionReportDialogController.GetData() in C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\Controller\ProductionReportDialogController.cs:line 104
at Dcp.Monitor.Controller.ProductionReportDialogController..ctor() in C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\Controller\ProductionReportDialogController.cs:line 44
at Dcp.Monitor.EntryPoint.Main() in C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\EntryPoint.cs:line 22
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Name and version of the database you are using:PostgreSQL 7.4
The generated SQL (show_sql=true):query one
Code:
SELECT
this.index as index1_,
this.start_time as start_time1_,
this.end_time as end_time1_,
this.fk_pss as fk_pss1_,
inventoryi1_.index as index0_,
inventoryi1_.quantity_on_hand as quantity3_0_,
inventoryi1_.sell_price as sell_price0_,
inventoryi1_.cost as cost0_,
inventoryi1_.unit as unit0_,
inventoryi1_.part_code as part_code0_,
inventoryi1_.description as descript5_0_
FROM
run_info this
left outer join inventory inventoryi1_ on this.fk_pss=inventoryi1_.index
WHERE
(this.start_time >= :p0 and this.end_time <= :p1)
Results
Code:
20;"2005-07-26 09:00:00";"2005-07-26 09:05:00";107;107;0;1.49;0;"EACH";"KOL863B";"blah"
21;"2005-07-26 09:10:00";"2005-07-26 09:15:00";109;109;5;1.6;1.5;"grams";"part1";"asdfjkl;"
22;"2005-07-26 09:20:00";"2005-07-26 09:25:00";111;111;5;1.6;1.5;"grams";"part1";"asdfjkl;"
23;"2005-07-26 09:30:00";"2005-07-26 09:35:00";112;112;5;1.6;1.5;"grams";"part1";"asdfjkl;"
24;"2005-07-26 09:40:00";"2005-07-26 09:45:00";113;113;5;2.1;2;"grams";"part2";"hgiehga"
query two
Code:
SELECT
inventoryi0_.index as index0_,
inventoryi0_.quantity_on_hand as quantity3_0_,
inventoryi0_.sell_price as sell_price0_,
inventoryi0_.cost as cost0_,
inventoryi0_.unit as unit0_,
inventoryi0_.part_code as part_code0_,
inventoryi0_.description as descript5_0_
FROM
inventory inventoryi0_
WHERE
inventoryi0_.index=:p0
Debug level Hibernate log excerpt:Code:
log4net: XmlHierarchyConfigurator: Configuration update mode [Merge].
log4net: XmlHierarchyConfigurator: Logger [root] Level string is [ALL].
log4net: XmlHierarchyConfigurator: Logger [root] level set to [name="ALL",value=-2147483648].
log4net: XmlHierarchyConfigurator: Loading Appender [rollingFile] type: [log4net.Appender.RollingFileAppender,log4net]
log4net: XmlHierarchyConfigurator: Setting Property [File] to String value [log.txt]
log4net: XmlHierarchyConfigurator: Setting Property [AppendToFile] to Boolean value [True]
log4net: XmlHierarchyConfigurator: Setting Property [RollingStyle] to RollingMode value [Date]
log4net: XmlHierarchyConfigurator: Setting Property [DatePattern] to String value [yyyy.MM.dd]
log4net: XmlHierarchyConfigurator: Setting Property [StaticLogFileName] to Boolean value [True]
log4net: PatternParser: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: XmlHierarchyConfigurator: Setting Property [ConversionPattern] to String value [%d [%t] %-5p %c [%x] <%X{auth}> - %m%n]
log4net: PatternParser: Converter [d] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [literal] Option [ [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [t] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [literal] Option [] ] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [p] Option [] Format [min=5,max=2147483647,leftAlign=True]
log4net: PatternParser: Converter [literal] Option [ ] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [c] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [literal] Option [ [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [x] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [literal] Option [] <] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [X] Option [auth] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [literal] Option [> - ] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [m] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: PatternParser: Converter [n] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: XmlHierarchyConfigurator: Setting Property [Layout] to object [log4net.Layout.PatternLayout]
log4net: RollingFileAppender: Type = [0], r0 = [1970.01.01], r1 = [1970.01.01]
log4net: RollingFileAppender: Type = [1], r0 = [1970.01.01], r1 = [1970.01.01]
log4net: RollingFileAppender: Type = [2], r0 = [1970.01.01], r1 = [1970.01.01]
log4net: RollingFileAppender: Type = [3], r0 = [1970.01.01], r1 = [1970.01.02]
log4net: RollingFileAppender: Searched for existing files in [C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\bin\Debug]
log4net: RollingFileAppender: curSizeRollBackups starts at [0]
log4net: RollingFileAppender: [2006.02.01] vs. [2006.02.01]
log4net: FileAppender: Opening file for writing [C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\bin\Debug\log.txt] append [True]
log4net: XmlHierarchyConfigurator: Created Appender [rollingFile]
log4net: XmlHierarchyConfigurator: Adding appender named [rollingFile] to logger [root].
log4net: XmlHierarchyConfigurator: Hierarchy Threshold []
log4net: DefaultRepositorySelector: Creating repository for assembly [NHibernate, Version=1.0.1.0, Culture=neutral, PublicKeyToken=154fdcb44c4484fc]
log4net: DefaultRepositorySelector: Assembly [NHibernate, Version=1.0.1.0, Culture=neutral, PublicKeyToken=154fdcb44c4484fc] Loaded From [C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\bin\Debug\NHibernate.DLL]
log4net: DefaultRepositorySelector: Assembly [NHibernate, Version=1.0.1.0, Culture=neutral, PublicKeyToken=154fdcb44c4484fc] does not have a RepositoryAttribute specified.
log4net: DefaultRepositorySelector: Assembly [NHibernate, Version=1.0.1.0, Culture=neutral, PublicKeyToken=154fdcb44c4484fc] using repository [log4net-default-repository] and repository type [log4net.Repository.Hierarchy.Hierarchy]
log4net: DefaultRepositorySelector: repository [log4net-default-repository] already exists, using repository type [log4net.Repository.Hierarchy.Hierarchy]
log4net: DefaultRepositorySelector: Creating repository for assembly [Spring.Core, Version=1.0.1.0, Culture=neutral, PublicKeyToken=65e474d141e25e07]
log4net: DefaultRepositorySelector: Assembly [Spring.Core, Version=1.0.1.0, Culture=neutral, PublicKeyToken=65e474d141e25e07] Loaded From [C:\Documents and Settings\Administrator\My Documents\Projects\Work\DCP\CS\MonitorTim\Monitor\bin\Debug\Spring.Core.DLL]
log4net: DefaultRepositorySelector: Assembly [Spring.Core, Version=1.0.1.0, Culture=neutral, PublicKeyToken=65e474d141e25e07] does not have a RepositoryAttribute specified.
log4net: DefaultRepositorySelector: Assembly [Spring.Core, Version=1.0.1.0, Culture=neutral, PublicKeyToken=65e474d141e25e07] using repository [log4net-default-repository] and repository type [log4net.Repository.Hierarchy.Hierarchy]
log4net: DefaultRepositorySelector: repository [log4net-default-repository] already exists, using repository type [log4net.Repository.Hierarchy.Hierarchy]
NHibernate :SELECT this.index as index1_, this.start_time as start_time1_, this.end_time as end_time1_, this.fk_pss as fk_pss1_, inventoryi1_.index as index0_, inventoryi1_.quantity_on_hand as quantity3_0_, inventoryi1_.sell_price as sell_price0_, inventoryi1_.cost as cost0_, inventoryi1_.unit as unit0_, inventoryi1_.part_code as part_code0_, inventoryi1_.description as descript5_0_ FROM run_info this left outer join inventory inventoryi1_ on this.fk_pss=inventoryi1_.index WHERE (this.start_time >= :p0 and this.end_time <= :p1)
NHibernate :SELECT inventoryi0_.index as index0_, inventoryi0_.quantity_on_hand as quantity3_0_, inventoryi0_.sell_price as sell_price0_, inventoryi0_.cost as cost0_, inventoryi0_.unit as unit0_, inventoryi0_.part_code as part_code0_, inventoryi0_.description as descript5_0_ FROM inventory inventoryi0_ WHERE inventoryi0_.index=:p0