3

TransactionException: Transaction not connected, or was disconnected] NHibernate.Transaction.AdoTransaction.CheckNotZombied() +108
NHibernate.Transaction.AdoTransaction.Rollback() +144

I'm getting the above error while while using NHibernate to query in the following way:

public IEnumerable<Service> GetAllServicesByOrgType(OrganisationType orgType)
{
return NHibernateSession
    .CreateCriteria<ServiceOrganisationType>()
    .Add(Restrictions.Eq("OrganisationType", orgType))            
    .List<ServiceOrganisationType>()
            .Select(x=>x.Service); 
}

Below is my database structure and FluentNHibernate mappings and models:

Database structure

Service:
- Id(PK)
- Name (nvarchar)

ServiceOrganisationType (composite PK on OrganisationTypeId and ServiceId):
- OrganisationTypeId (PK)
- ServiceId (PK)
- LastUpdated
- LastUpdatedById

OrganisationType:
- Id (PK)
- OrganisationType (nvarchar)

ServiceOrganisationTypeMap:

public class ServiceOrganisationTypeMap : ClassMap<ServiceOrganisationType>
{
    public ServiceOrganisationTypeMap()
    {
        CompositeId()
            .KeyReference(x => x.Service, "ServiceId")
            .KeyProperty(x => x.OrganisationType, "OrganisationTypeId");
        References(x => x.LastUpdatedBy);
        Map(x => x.LastUpdated);
    }
}

ServiceMap:

public class ServiceMap : ClassMap<Service>
{
    /// <summary>
    /// Initializes a new instance of the ServiceMap class.
    /// </summary>
    public ServiceMap()
    {
        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name);
        HasMany(x => x.ServiceOrganisationTypes)
            .KeyColumn("ServiceId")
            .Inverse()
            .Cascade
            .AllDeleteOrphan();

        // Other mappings...
    }
}

OrganisationType is an Enum:

public enum OrganisationType : long
{
    FirstOrgTypeExample = 1,
    SecondOrgTypeExample = 10,
    ThirdOrgTypeExample = 30
}

Service model class:

[Serializable]
public class Service : DomainObject
{
    // Other model properties...

    public virtual IList<ServiceOrganisationType> ServiceOrganisationTypes { get; set; }
}

ServiceOrganisationType model class:

[Serializable]
public class ServiceOrganisationType : AuditedObject
{
    [NotNull]
    public virtual OrganisationType OrganisationType { get; set; }

    [NotNull]
    public virtual Service Service { get; set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        var t = obj as ServiceOrganisationType;
        if (t == null)
            return false;
        if (OrganisationType == t.OrganisationType && Service == t.Service)
            return true;
        return false;
    }

    public override int GetHashCode()
    {
        return (OrganisationType + "|" + Service.Id).GetHashCode();
    }
}

For the Enum, i'm also using the EnumConvention class described within the answer of this post: Enum to integer mapping causing updates on every flush. So my Accept method has the following in it:

public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
    criteria.Expect(
        // ... Other arguments ||

         // We want all instance of OrganisationType to map to long
         x.Property.PropertyType == typeof(OrganisationType)

         );
}

I'm guessing that the CheckNotZombied is a symptom of something else. When i check NHProf it shows a SQL error - "System.Data.SqlClient.SqlException: Error converting data type nvarchar to bigint" - and that NHib generated the following sql while querying the ServiceOrganisationType table:

SELECT this_.ServiceId          as ServiceId63_0_,
       this_.OrganisationTypeId as Organisa2_63_0_,
       this_.LastUpdated        as LastUpda3_63_0_,
       this_.LastUpdatedById    as LastUpda4_63_0_
FROM   MyDb.dbo.[ServiceOrganisationType] this_
WHERE  this_.OrganisationTypeId = 'FirstOrgTypeExample' /* @p0 */

In the WHERE clause it's using the string value for the enum ('FirstOrgTypeExample') instead of the long value. I've tried casting the OrganisationType to a long during the criteria query, but then a mapping exception is thrown saying:

NHibernate.QueryException: Type mismatch in NHibernate.Criterion.SimpleExpression: OrganisationType expected type MyProduct.MyProject.Core.OrganisationType, actual type System.Int64

Can anyone help me work out how i can get NHibernate to use the enum value in the generated sql?

Thanks

Community
  • 1
  • 1
Robbie
  • 18,750
  • 4
  • 41
  • 45

2 Answers2

1

The issue was with my EnumConvention. It wasn't dealing with the composite key. The solution was found in this post: How can I make composite key enums use int in fluent nhibernate with a convention?

Community
  • 1
  • 1
Robbie
  • 18,750
  • 4
  • 41
  • 45
0

Is the OrganisationTypeId nullable? If so you would need to ammed your Accept method to allow for this otherwise it will remain as a string value. Something like the following should work.

public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
    criteria.Expect((x => x.Property.PropertyType.IsEnum &&
             x.Property.PropertyType == typeof(OrganisationType))  ||
            (x.Property.PropertyType.IsGenericType && 
             x.Property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) &&
             x.Property.PropertyType.GetGenericArguments()[0].IsEnum)
            );
}
Fraser
  • 15,275
  • 8
  • 53
  • 104