Текущее сопоставление перечислений NHibernate с помощью составного ключа - CheckNotZombied - PullRequest
3 голосов
/ 12 февраля 2012

TransactionException: транзакция не подключена или была отключена] NHibernate.Transaction.AdoTransaction.CheckNotZombied () + 108
NHibernate.Transaction.AdoTransaction.Rollback () + 144

Я получаю вышеуказанную ошибку при использовании NHibernate для запроса следующим образом:

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

Ниже представлена ​​структура моей базы данных и отображения и модели FluentNHibernate:

Структура базы данных

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 - это Enum:

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

Класс обслуживания модели:

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

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

Класс модели ServiceOrganisationType:

[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();
    }
}

Для Enum я также использую класс EnumConvention, описанный в ответе на этот пост: Перечисление Enum в целочисленное отображение, вызывающее обновления при каждом сбросе . Таким образом, мой метод Accept содержит следующее:

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)

         );
}

Я предполагаю, что CheckNotZombied является симптомом чего-то другого. Когда я проверяю NHProf, он показывает ошибку SQL - «System.Data.SqlClient.SqlException: Ошибка преобразования типа данных nvarchar в bigint» - и что NHib сгенерировал следующий sql при запросе таблицы ServiceOrganisationType:

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 */

В предложении WHERE используется строковое значение для перечисления ('FirstOrgTypeExample') вместо значения long . Я пытался преобразовать OrganisationType в long во время запроса критерия, но затем выдается исключение сопоставления, говоря:

NHibernate.QueryException: несоответствие типов в NHibernate.Criterion.SimpleExpression: ожидаемый тип OrganisationType MyProduct.MyProject.Core.OrganisationType, фактический тип System.Int64

Может кто-нибудь помочь мне разобраться, как заставить NHibernate использовать значение enum в сгенерированном sql?

Спасибо

Ответы [ 2 ]

1 голос
/ 17 февраля 2012

Проблема была с моей EnumConvention. Он не имел дело с составным ключом. Решение было найдено в этом посте: Как я могу заставить составные ключевые перечисления использовать int в беглом nhibernate с соглашением?

0 голосов
/ 13 февраля 2012

Возможно ли значение OrganisationTypeId обнуляется? Если это так, вам нужно добавить в свой метод Accept, чтобы разрешить это, иначе он останется строковым значением. Должно работать что-то вроде следующего.

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)
            );
}
...