我们正在开发一个NHibernate项目,我们需要实现NHibernate IUserType
接口。所以我们做了,到目前为止它工作正常(我们尚未开始测试NullSafeSet
方法)。但是,我们有一个问题:我们需要知道我们映射的属性,以便能够返回正确的结果。
我们需要映射的值作为int
存储在数据库中,我们需要根据此值创建代码对象。为了能够创建Code对象,我们需要string
以及前面提到的int
。这个string
是我们映射的属性的名称。
我已经发现names
参数包含属性的NHibernate SQL别名(它的形式为:“IS69_6_”),但我不知道这个值是否保持不变(当我调试它似乎保持不变)。
一些代码澄清: CodeTypeMapper.cs
public class CodeTypeMapper : IUserType
{
public new bool Equals(object x, object y)
{
return x != null && x.Equals(y);
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
/********** Code relevant to the question: **********/
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var key = (int?)NHibernateUtil.Int32.NullSafeGet(rs, names[0]);
if (key == null) return null;
// So here we need to be able to get the correct code.
// In order to get the correct code, we need the key (fetched above)
// but we also need the name of the property that we are mapping
// which has a dummy value in this example.
Code code = MasterMetaProvider.MasterMeta.GetCode("PropertyName", (int)key);
if (code == null) return null;
// Now that we have the Code object, we can use it to return the proper result
var result = new NetworkObjectEnum((int)key, code.CodeDescEn);
return result;
}
/***************************************************/
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (value == null)
{
NHibernateUtil.Int32.NullSafeSet(cmd, null, index);
}
else
{
value = int.Parse(value.ToString());
NHibernateUtil.Int32.NullSafeSet(cmd, value, index);
}
}
public object DeepCopy(object value)
{
return value;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
public SqlType[] SqlTypes
{
get
{
var types = new SqlType[1];
types[0] = new SqlType(DbType.String);
return types;
}
}
public Type ReturnedType
{
get { return typeof(NetworkObjectEnum); }
}
public bool IsMutable
{
get { return false; }
}
}
NHibernate映射代码:
// We need this Property's name
Map(x => x.PropertyName).Column("PropertyNameInDB").CustomType<CodeTypeMapper>();
<小时/>
所以我想问的问题是:是否可以在CodeTypeMapper
类中访问上述属性的名称?
提前致谢。
此致 Yanik Ceulemans
为了澄清我的问题,我将举一个例子:假设有一个代码表,用于指定城市,交通类型等......:
+----+-----------+------------+-----------+
| id | code_type | code_value | code_desc |
+----+-----------+------------+-----------+
| 1 | city | 5 | Antwerp |
| 2 | city | 8 | Brussels |
| 3 | city | 1 | Ghent |
| 4 | transport | 1 | boat |
| 5 | transport | 8 | plane |
| 6 | transport | 9 | car |
+----+-----------+------------+-----------+
接下来,我们有一个旅行表,它以下列方式使用此代码表:
+----+------+-------------------+-----------+
| id | city | other_column | transport |
+----+------+-------------------+-----------+
| 1 | 5 | some random value | 1 |
| 2 | 8 | randomness | 8 |
| 3 | 1 | a value | 9 |
+----+------+-------------------+-----------+
正如您所看到的:如果我们想知道代码的描述,我们知道我们需要从代码表中获取什么值,方法是查看列名,以及旅行表中该列中的值。 / p>
c#class Travel
可能看起来像这样:
public class Travel
{
public int Id { get; set; }
public int City { get; set; }
public string OtherColumn { get; set; }
public int Transport { get; set; }
}
所以我的问题是:在映射Travel类时,是否有可能在运行时在IUserType
实现中获取属性名称“city”,以便能够从代码表中获取正确的值? (注意:我无法更改数据库设计。)
答案 0 :(得分:2)
这种设计被称为“神桌”,你有我的同情心。当我开始时,我们的主要产品就有其中一种,我花了一年的时间将其标准化。
在重构之前,我使用视图对NHibernate进行了映射,以实际对其进行规范化。也就是说,为城市,交通等创建一个视图,并将它们映射为就像它们是表格一样。我发现您无法更改架构,但如果您可以添加视图,这是一个很好的解决方案。
备选方案1:为代码表中的每种类型创建一个IUserType实现。
备选方案2:在使用视图之前,我使用了NHibernate为映射添加where子句的能力。我记得这种方法存在缺陷,其中一种我认为where子句并不总是在查询中按预期应用。使用Fluent NHibernate,映射看起来像这样:
public abstract Class CodeTableBase
{
public virtual int Id { get; protected set; }
public virtual string CodeType { get; protected set; }
public virtual int Value { get; protected set; }
public virtual string Description { get; protected set; }
}
public class City : CodeTableBase {}
public abstract class CodeTableMap<T> : ClassMap<T> where T : CodeTableBase
{
public CodeTableMap()
{
Table("CodeTable");
Id(x => Id, "id").your id generation strategy
CodeType(x => x.CodeType, "code_type");
Value(x => x.Value, "code_value");
Description(x => x.Description, "code_description");
}
public CodeTableMap(string codeType) : this()
{
Where("code_type = '" + codeType + '"); // may need to use property name
}
}
public class CityMap : CodeTableMap<City>
{
public CityMap : base("city") {}
}
答案 1 :(得分:0)
我不确定你的意思,但也许你需要这样的东西:
实现IParameterizedType,您可以发送映射属性的名称:
Fluent NHibernate不提供此功能,但您可以使用xml文件。
其他不太优雅的解决方案:
var propertyName = GetPropertyName(owner.GetType(), owner, typeof(YourAttribute));
public static string GetPropertyName(Type entityType, object entity, Type attributeType)
{
if (entity == null) return null;
var propertyInfo = GetPropertyInfo(entityType, attributeType);
return propertyInfo == null ? null : propertyInfo.Name;
}
public static PropertyInfo GetPropertyInfo(Type entityType, Type attributeType)
{
return entityType.GetProperties().FirstOrDefault(prop => prop.GetCustomAttributes(false)
.Count(x => x.GetType() == attributeType) > 0);
}