views:

23

answers:

1

Hi everyone, I have what strikes me as a very unusual behavior from Linq for NHibernate.

In general, all my entity classes are working just fine, but one of them throws a "NonUniqueResult" exception from the NHibernate namespace under the following condition.

If I call the following:

getSession<MyClass>().Linq<MyClass>().Count();

it throws the exception. If I call

getSession<MyClass>().Linq<MyClass>().ToList().Count();

it does not.

There's no problem with the other CRUD operations for this class, so I don't think it's my mappings.

My guess is that it has something to do with how the Count() operator ultimately gets materialized as a SQL query, but beyond that I'm not sure where to look.

Updated to include mapping of the class in question

<?xml version="1.0" encoding="utf-16"?>
<hibernate-mapping  auto-import="true" default-lazy="false" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:nhibernate-mapping-2.2">
  <class name="My.App.MyClass, My.App" table="MyClass">
<id name="Id" access="property" column="Id" type="System.Guid" unsaved-value="00000000-0000-0000-0000-000000000000">
  <generator class="guid.comb">
  </generator>
</id>
<version name="TimeStamp" access="property" column="TimeStamp" type="Int32" />
<property name="CreatedOn" access="property" type="System.DateTime">
  <column name="CreatedOn"/>
</property>
<property name="Ticker" access="property" type="Int32">
  <column name="Ticker"/>
</property>
<property name="DifferentTicker" access="property" type="Int32">
  <column name="DifferentTicker"/>
</property>
<property name="SomeDecimal" access="property" type="System.Decimal">
  <column name="SomeDecimal"/>
</property>
<property name="StillAnotherTicker" access="property" type="Int32">
  <column name="StillAnotherTicker"/>
</property>
<property name="IsActive" access="property" type="Boolean">
  <column name="IsActive"/>
</property>
<many-to-one name="RelatedThing" access="property" class="My.App.RelatedThing, My.App" column="RelatedThingId" lazy="proxy" />
<many-to-one name="OtherRelatedThing" access="property" class="My.App.OtherRelatedThing, My.App" column="OtherRelatedThingId" lazy="proxy" />
<bag name="_schedule" access="property" table="Schedule" lazy="false" cascade="all-delete-orphan">
  <key column="MyClassId" />
  <one-to-many class="My.App.Schedule, My.App" />
</bag>
<bag name="Vectors" access="property" table="Vectors" lazy="false">
  <key column="MyClassId" />
  <many-to-many class="My.App.Channels.BaseVector, My.App" column="vectorid"/>
</bag>
</class>
</hibernate-mapping>
A: 

Both version work fine for me in a simple unit test. In this example:

using ( var tx = Session.BeginTransaction() )
{
    int count = Session.Linq<Customer>().Count();
    Assert.Equal( 2, count );

    count = Session.Linq<Customer>().ToList().Count();
    Assert.Equal( 2, count );

    tx.Commit();
}

The first query performs a SQL count:

NHibernate: SELECT count(*) as y0_ FROM "Customer" this_

And the second gets all returns all items into a temporary list and then calls Count() on the list:

NHibernate: SELECT this_.Id as Id9_0_, this_.Name as Name9_0_ FROM "Customer" this_

This leads me to believe that there might be an issue with your mappings. And you really want to get the first one working cause the second won't scale for large datasets.

David Lynch
Agreed on the performance hit. I really don't know what it could be on the mapping, I've added the class in question's mapping above in case you can see. I'm using ActiveRecord to do the mappings, so that's what it generated. And again, not seeing errors in other classes, and this one works fine for all other operations.
Dr. Evil
But the error doesn't have anything to do with the Count() since it's not part of the SQL. I would assume you get the same error with "getSession<MyClass>().Linq<MyClass>().ToList()"?
David Lynch