【问题标题】:Mapping enum with fluent nhibernate使用流利的 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 指定任何映射。

问题是:

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

谢谢!

【问题讨论】:

    标签: .net enums fluent-nhibernate


    【解决方案1】:

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

    这样做怎么样:

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

    自定义类型处理一切:)

    【讨论】:

    【解决方案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>()
    

    【讨论】:

    【解决方案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>();
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多