C# 将标志枚举属性映射到单独的表

C# 将标志枚举属性映射到单独的表,c#,nhibernate,fluent-nhibernate,C#,Nhibernate,Fluent Nhibernate,想象这样一个类: public class MyEntity : Entity { public virtual States States { get; set; } } [Flags] public enum States { None, State1 = 1, State2 = 2, State3 = 4, State4 = 8 } Map(y => y.States).Columns.Add("IS_STATE1_SET", "I

想象这样一个类:

public class MyEntity : Entity
{
    public virtual States States { get; set; }
}

[Flags]
public enum States
{
    None,
    State1 = 1,
    State2 = 2,
    State3 = 4,
    State4 = 8
}
Map(y => y.States).Columns.Add("IS_STATE1_SET", "IS_STATE2_SET",
                               "IS_STATE3_SET", "IS_STATE4_SET")
                  .CustomType<StatesUserType>();
我想将其映射到此表:

TABLE MY_ENTITY
ID: PK
STATES_ID : FK to MY_ENTITY_STATES

TABLE MY_ENTITY_STATES
ID: PK
IS_STATE1_SET (bit)
IS_STATE2_SET (bit)
IS_STATE3_SET (bit)
IS_STATE4_SET (bit)
这可能吗

这是一个遗留方案,我无法更改数据库


根据要求,以下是一些示例数据:

表MY_实体

ID | STATES_ID
---+----------
14 | 35
表MY_实体_状态

ID | IS_STATE1_SET | IS_STATE2_SET | IS_STATE3_SET | IS_STATE4_SET
---+---------------+---------------+---------------+--------------
35 | 0             | 1             | 0             | 1

这将导致ID为14的
MyEntity
实例中的
States
属性中的值为
States.State2 | States.State4

这是一个两步解决方案

首先,使用将MY_ENTITY_State记录带出,然后编写一个将标志转换为列的
IUserType


查看示例。

我创建了一个简单的
IUserType
实现来实现映射。不需要实现
ICompositeUserType

public class StatesUserType : IUserType
{
    private static readonly SqlType[] _sqlTypes = {
           NHibernateUtil.Int16.SqlType, NHibernateUtil.Int16.SqlType, 
           NHibernateUtil.Int16.SqlType, NHibernateUtil.Int16.SqlType  };

    public Type ReturnedType
    {
        get { return typeof(States); }
    }

    public SqlType[] SqlTypes
    {
        get { return _sqlTypes; }
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var result = States.None;
        if (((short)rs[names[0]]) == 1)
            result |= States.State1;
        if (((short)rs[names[1]]) == 1)
            result |= States.State2;
        if (((short)rs[names[2]]) == 1)
            result |= States.State3;
        if (((short)rs[names[3]]) == 1)
            result |= States.State4;

        return result;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        if (value == null)
            return;
        if (value.GetType() != typeof(States))
            return;
        var states = (States)value;
        cmd.Parameters[index] = states.HasFlag(States.State1);
        cmd.Parameters[index] = states.HasFlag(States.State2);
        cmd.Parameters[index] = states.HasFlag(States.State3);
        cmd.Parameters[index] = states.HasFlag(States.State4);
    }

    public bool IsMutable
    {
        get { return false; }
    }

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

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

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

    public bool Equals(object x, object y)
    {
        return object.Equals(x, y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }
}
映射需要如下所示:

public class MyEntity : Entity
{
    public virtual States States { get; set; }
}

[Flags]
public enum States
{
    None,
    State1 = 1,
    State2 = 2,
    State3 = 4,
    State4 = 8
}
Map(y => y.States).Columns.Add("IS_STATE1_SET", "IS_STATE2_SET",
                               "IS_STATE3_SET", "IS_STATE4_SET")
                  .CustomType<StatesUserType>();
Map(y=>y.States).Columns.Add(“IS_STATE1_SET”,“IS_STATE2_SET”,
“是否为状态3集”、“是否为状态4集”)
.CustomType();

谢谢,看起来很棒。我明天会测试它。你能用Fluent NHibernate提供一个映射的草图吗?.Join(某物…映射(属性)。Type(类型)…类似于:-)我不使用Fluent;你必须用智能感知来解决这个问题。我不太确定,怎么做。在您提供的链接中,
ICompositeUserType
的实现作为具有两个属性和两列的类之间的映射引入。但是我只有一个没有属性的枚举。例如,对于
PropertyTypes
PropertyNames
,我会返回什么?我相信您可以返回类型状态的简单属性(称为“值”)。与此同时,我尝试使用
IUserType
而不是
ICompositeUserType
。它运行得很好,请参阅我的。然而,我仍然有一个加入的问题,请看。