【问题标题】:Fluent NHibernate Enum Mapping with Composite key - CheckNotZombiedFluent NHibernate Enum Mapping with Composite key - CheckNotZombied
【发布时间】:2012-02-12 17:27:09
【问题描述】:

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

服务地图:

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 中使用枚举值?

谢谢

【问题讨论】:

    标签: nhibernate fluent-nhibernate enumeration


    【解决方案1】:

    问题出在我的 EnumConvention 上。它没有处理复合键。在这篇文章中找到了解决方案:How can I make composite key enums use int in fluent nhibernate with a convention?

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • OrganisationTypeId 列不可为空,所以我猜这不适用
      猜你喜欢
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多