使用流利的 nhibernate 映射枚举

Posted

技术标签:

【中文标题】使用流利的 nhibernate 映射枚举【英文标题】:Mapping enum with fluent nhibernate 【发布时间】:2010-12-01 18:25:32 【问题描述】:

我正在按照http://wiki.fluentnhibernate.org/Getting_started 教程使用 Fluent NHibernate 创建我的第一个 NHibernate 项目

我有两张桌子

1) 带有字段的帐户

Id
AccountHolderName
AccountTypeId

2) 带字段的 AccountType

Id
AccountTypeName

目前账户类型可以是储蓄或活期 所以表 AccountTypes 存储 2 行 1 - 储蓄 2 - 当前

对于AccoutType 表我已经定义了枚举

public enum AccountType 
    Savings=1,
    Current=2

对于 Account 表,我定义了实体类

public class Account 
    public virtual int Id get; private set;
    public virtual string AccountHolderName get; set;
    public virtual string AccountType get; set;

流畅的nhibernate映射是:

public AgencyMap() 
    Id(o => o.Id);
    Map(o => o.AccountHolderName);
    Map(o => o.AccountType);

当我尝试运行解决方案时,它给出了一个异常 - InnerException = "(XmlDocument)(2,4): XML validation error: The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has内容不完整。预期的可能元素列表:命名空间“ur...”中的“元、子选择、缓存、同步、注释、元组、id、复合 ID”。

我猜这是因为我没有为 AccountType 指定任何映射。

问题是:

    如何使用 AccountType 枚举 而不是 AccountType 类? 也许我走错了路。有没有更好的方法来做到这一点?

谢谢!

【问题讨论】:

【参考方案1】:

以下显然不再有效https://***.com/a/503327/189412

这样做怎么样:

public AgencyMap() 
    Id(o => o.Id);
    Map(o => o.AccountHolderName);
    Map(o => o.AccountType).CustomType<AccountType>();

自定义类型处理一切:)

【讨论】:

啊哈!我正在使用 CustomSqlType 但它不起作用!我需要的是 CustomType! AcountType 是一个枚举,因此所有实体在加载后都会变脏。见***.com/questions/3531937/… 这似乎是正确的,但会生成“幻影”更新。正确的映射是:CustomType。否则,就像 schoetbi 所说,实体在加载后是脏的。来源:groups.google.com/forum/#!searchin/fluent-nhibernate/enum/… 这不再有效!您需要在更新版本的 FNH 中使用 .CustomType>() 。见***.com/a/503327/189412【参考方案2】:
public class Account 
    public virtual int Id get; private set;
    public virtual string AccountHolderName get; set;
    public virtual AccountType AccountType get; set;


public AgencyMap() 
    Id(o => o.Id);
    Map(o => o.AccountHolderName);
    Map(o => o.AccountType);

Fluent NHibernate 默认将枚举值保存为字符串,如果你想覆盖你需要为其提供约定。比如:

public class EnumConvention :
    IPropertyConvention, 
    IPropertyConventionAcceptance

    #region IPropertyConvention Members

    public void Apply(IPropertyInstance instance)
    
        instance.CustomType(instance.Property.PropertyType);
    

    #endregion

    #region IPropertyConventionAcceptance Members

    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    
        criteria.Expect(x => x.Property.PropertyType.IsEnum ||
        (x.Property.PropertyType.IsGenericType && 
         x.Property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) &&
         x.Property.PropertyType.GetGenericArguments()[0].IsEnum)
        );
    

    #endregion

几乎忘记了您还需要将约定添加到流利的配置中。您在添加映射的同一位置执行此操作:

.Mappings(m => m.FluentMappings.AddFromAssemblyOf<BillingRecordMap>()
.Conventions.AddFromAssemblyOf<EnumConvention>()

【讨论】:

查看这篇文章/评论,了解如何扩展它以支持可为空的枚举:***.com/questions/439003/… 我用你的建议 Mustafa 更新了代码。非常感谢!【参考方案3】:

实现这一点的好方法是实现接口 IUserType 并创建一个具有写入和读取规则的 CustomType,这是一个布尔示例:

 public class CharToBoolean : IUserType

    public SqlType[] SqlTypes => new[]  NHibernateUtil.String.SqlType ;

    public Type ReturnedType => typeof(bool);

    public bool IsMutable =>true;

    public object Assemble(object cached, object owner)
    
        return (cached);
    

    public object DeepCopy(object value)
    
        return (value);
    

    public object Disassemble(object value)
    
        return (value);
    

    public new bool Equals(object x, object y)
    
        if (ReferenceEquals(x, y)) return true;

        var firstObject = x as string;
        var secondObject = y as string;

        if (string.IsNullOrEmpty(firstObject) || string.IsNullOrEmpty(secondObject)) return false;

        if (firstObject == secondObject) return true;
        return false;
    

    public int GetHashCode(object x)
    
        return ((x != null) ? x.GetHashCode() : 0);
    

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    
        var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);

        if (obj == null) return null;

        var value = (string)obj;

        return value.ToBoolean();
    

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    
        if(value != null)
        
            if ((bool)value)
            
                ((IDataParameter)cmd.Parameters[index]).Value = "S";
            
            else
            
                ((IDataParameter)cmd.Parameters[index]).Value = "N";
            
        
        else
        
            ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
        
    
    public object Replace(object original, object target, object owner)
    
        return original;
    

映射:

  this.Map(x => x.DominioGenerico).Column("fldominiogen").CustomType<CharToBoolean>();

这是一个示例,但您可以使用其他类型进行此操作。

【讨论】:

以上是关于使用流利的 nhibernate 映射枚举的主要内容,如果未能解决你的问题,请参考以下文章

您如何在流利的 nhibernate 中映射和使用连接表?

流利的nhibernate映射多对多配置错误

in (ASP.NET) 之外的流利 NHibernate 错误映射程序集

流利的NHibernate显示不使用给定的属性名称

流利的 NHibernate 多对多创建附加表

使用 2 种策略通过 fluent nhibernate 映射类层次结构