简体   繁体   English

NHibernate IUserType获取映射的属性名称

[英]NHibernate IUserType get mapped property name

We are working on an NHibernate project where we needed to implement the NHibernate IUserType interface. 我们正在一个NHibernate项目中,我们需要实现NHibernate IUserType接口。 So we did and so far it works fine (we haven't gotten around to testing the NullSafeSet method yet). 因此,我们做到了,到目前为止效果很好(我们尚未测试NullSafeSet方法)。 However, we have 1 problem: We need to know what property we are mapping in order to be able to return the correct result. 但是,我们有1个问题:我们需要知道我们要映射的属性,以便能够返回正确的结果。

Situation: 情况:

The value which we need to map is stored in the DB as an int , we need to create a Code object from this value. 我们需要映射的值以int形式存储在数据库中,我们需要根据该值创建一个Code对象。 To be able to create the Code object, we require a string alongside with the previously mentioned int . 为了能够创建Code对象,我们需要一个string以及前面提到的int This string is the name of the property we are mapping. string是我们正在映射的属性的名称。

I already discovered that the names parameter contains the NHibernate SQL alias of the property (it was something in the form of: "IS69_6_") but I don't know whether or not this value stays the same (When i debugged it seemed to remain the same). 我已经发现names参数包含该属性的NHibernate SQL别名(它的形式为:“ IS69_6_”),但是我不知道此值是否保持不变(当我调试时,它似乎仍然存在相同)。

Some code to clarify: CodeTypeMapper.cs 需要澄清的一些代码: 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; }
    }
}

The NHibernate Mapping code: NHibernate映射代码:

// We need this Property's name
Map(x => x.PropertyName).Column("PropertyNameInDB").CustomType<CodeTypeMapper>();


Question: 题:

So the question I want to ask: Is it possible to access the above property's name in the CodeTypeMapper class ? 所以我想问一个问题:是否可以在CodeTypeMapper类中访问上述属性的名称?

Thanks in advance. 提前致谢。

Regards, Yanik Ceulemans 此致Yanik Ceulemans


Update 23 Sept 2013: 2013年9月23日更新:

As an attempt to clarify my question, I will give an example: Say there is a code table that specifies cities, types of transport, etc...: 为了澄清我的问题,我将举一个例子:假设有一个代码表,用于指定城市,交通类型等:

+----+-----------+------------+-----------+
| 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       |
+----+-----------+------------+-----------+

Next, we have a travel table that uses this code table in the following fashion: 接下来,我们有一个旅行表,该旅行表以以下方式使用此代码表:

+----+------+-------------------+-----------+
| id | city |   other_column    | transport |
+----+------+-------------------+-----------+
|  1 |    5 | some random value |         1 |
|  2 |    8 | randomness        |         8 |
|  3 |    1 | a value           |         9 |
+----+------+-------------------+-----------+

As you can see: if we want to know the description for a code, we know what value we need to take from the code table by looking at the column name, and the value in that column from the travel table. 如您所见:如果我们想了解代码的说明,那么通过查看列名以及旅行表中该列中的值,我们知道需要从代码表中获取什么值。

The c# class Travel will probably look something like this: C#类Travel可能看起来像这样:

public class Travel
{
    public int Id { get; set; }
    public int City { get; set; }
    public string OtherColumn { get; set; }
    public int Transport { get; set; }
}

So my question is: Is it possible when mapping the Travel class, to get the property name "city" inside the IUserType implementation at runtime in order to be able to grab the correct value from the code table ? 所以我的问题是:映射Travel类时,是否有可能在运行时在IUserType实现内获取属性名称“ city”,以便能够从代码表中获取正确的值? (note: I cannot change the DB design.) (注意:我不能更改数据库设计。)

This design is known as a "god table" and you have my sympathies. 这种设计被称为“神表”,您对此表示同情。 Our main product had one of these when I started and it took me a year to normalize it. 我刚开始时的主要产品就是其中之一,我花了一年的时间对其进行标准化。

Before the refactoring, I mapped this with NHibernate by using views to virtually normalize it. 在重构之前,我通过使用视图将其虚拟化将其与NHibernate映射。 That is, create a view for city, transport, etc. and map those as if they were tables. 即,为城市,交通等创建视图,并将其映射为表格。 I see that you can't change the schema but if you can add views this is a good solution. 我看到您无法更改架构,但是如果您可以添加视图,那么这是一个很好的解决方案。

Alternative 1: Create an IUserType implementation for each type in your code table. 备选方案1:为代码表中的每种类型创建IUserType实现。

Alternative 2: Prior to using views, I used NHibernate's ability to add a where clause to the mapping. 备选方案2:在使用视图之前,我使用NHibernate的功能向映射添加where子句。 I remember that there were drawbacks to this approach, one of which I think was that the where clause was not always applied as expected in queries. 我记得这种方法有一些缺点,我认为其中之一是,where子句并非总是按预期在查询中应用。 Using Fluent NHibernate the mapping would look like this: 使用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") {}
}

I'm not sure what you mean, but maybe you need something like this: 我不确定您的意思,但也许您需要这样的东西:

Here 这里


Implementing IParameterizedType you can send in mapping the name of the property: 实现IParameterizedType时,可以在映射中发送属性名称:

Here 这里

Fluent NHibernate does not provide capability to this but you can use xml files. Fluent NHibernate不提供此功能,但是您可以使用xml文件。

Mapping 制图


Other not much elegant solution: 其他没有太多优雅的解决方案:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM