使用复合键的流畅NHibernate枚举映射 - CheckNotZombied

时间:2012-02-12 17:27:09

标签: nhibernate fluent-nhibernate enumeration

  

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是一个枚举:

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 to integer mapping causing updates on every flush。所以我的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在查询ServiceOrganisationType表时生成了以下sql:

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在生成的sql中使用枚举值吗?

由于

2 个答案:

答案 0 :(得分:1)

问题出在我的EnumConvention上。它没有处理复合键。该帖子中提供了解决方案:How can I make composite key enums use int in fluent nhibernate with a convention?

答案 1 :(得分:0)

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