Mapping a bit field (FlagsAttribute) to multiple columns using NHibernate?
In the question, Mapping to an Enum bit flag in Nhibernate, the accepted answer suggests to simply use an integer field to store the bit mask of an enumeration type. While this certainly works, I'd prefer not to use this approach because it obfuscates the information in the database.
Let's say I have this enumeration:
[Flags]
public enum Status
{
None = 0,
Foo = 1,
Bar = 2,
Baz = 4
}
I would like to use the following schema to represent it:
CREATE TABLE Widgets
(
Id int NOT NULL IDENTITY(1, 1) PRIMARY KEY,
Description nvarchar(100) NOT NULL,
-- Status fields start here
IsFoo bit NOT NULL,
IsBar bit NOT NULL,
IsBaz bit NOT NULL
)
Can I do this using NHiber开发者_如何学Pythonnate - preferably without a lot of ugly hacks? If so, how?
If not, are there any alternatives which maintain the discoverability of the data, other than defining every single possible combination of flags in a config table?
(Note: I'd prefer a Fluent NHibernate solution, but I can probably muddle through an XML mapping.)
Apologies for not being a complete answer here I've struggled setting up NHib/fluent on this machine. I've taken an old custom type I had and changed it to meet your status enum. I think in later versions of nHibernate some of the method interfaces may have changed, but I think it gives a good starting point.
class StatusUserType : ICompositeUserType
{
public object GetPropertyValue(object component, int property)
{
// 0 = foo
// 1 = bar
// 2 = baz
Status status = (Status)component;
if (property == 0)
{
return status |= Status.Foo;
}
else if (property == 1)
{
return status |= Status.Bar;
}
else
{
return status |= Status.Baz;
}
}
public void SetPropertyValue(object component, int property, object value)
{
throw new NotImplementedException();
}
public new bool Equals(object x, object y)
{
if (x == y) return true;
if (x == null || y == null) return false;
return x.Equals(y);
}
public object NullSafeGet(System.Data.IDataReader dr, string[] names, ISessionImplementor session, object owner)
{
if (dr == null)
{
return null;
}
string fooColumn = names[0];
string barColumn = names[1];
string bazColumn = names[2];
bool isFoo = NHibernateUtil.Boolean.NullSafeGet(dr, fooColumn, session, owner);
bool isBar = NHibernateUtil.Boolean.NullSafeGet(dr, barColumn, session, owner);
bool isBaz = NHibernateUtil.Boolean.NullSafeGet(dr, bazColumn, session, owner);
Status status = (isFoo ? Status.Foo : Status.None) | (isBar ? Status.Bar : Status.None) | (isBaz ? Status.Baz : Status.None);
return status;
}
public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index, ISessionImplementor session)
{
if (value == null)
return;
Status status = (Status)value;
bool isFoo = ((status & Status.Foo) != 0);
bool isBar = ((status & Status.Bar) != 0);
bool isBaz = ((status & Status.Baz) != 0);
NHibernateUtil.Boolean.NullSafeSet(cmd, isFoo, index, session);
NHibernateUtil.Boolean.NullSafeSet(cmd, isBar, index + 1, session);
NHibernateUtil.Boolean.NullSafeSet(cmd, isBaz, index + 2, session);
}
public object DeepCopy(object value)
{
return (Status)value;
}
public object Disassemble(object value, ISessionImplementor session)
{
return DeepCopy(value);
}
public object Assemble(object cached, ISessionImplementor session, object owner)
{
return DeepCopy(cached);
}
public string[] PropertyNames
{
get { return new string[3] { "IsFoo", "IsBar", "IsBaz" }; }
}
public IType[] PropertyTypes
{
get
{
return new IType[3] { NHibernateUtil.Boolean, NHibernateUtil.Boolean, NHibernateUtil.Boolean };
}
}
public Type ReturnedClass
{
get { return typeof(Status); }
}
public bool IsMutable
{
get { return false; }
}
well, this is at least a little bit ugly:
You can map those 3 columns to private fields of your entity, and then compute the Status
property from those 3 fields.
something to the effect of:
public class Kuku
{
private virtual bool IsFoo {get; set;}
private virtual bool IsBar {get; set;}
private virtual bool IsBaz {get; set;}
public virtual Status Stat
{
get
{
Status retval = Status.None;
if (IsFoo)
{
retVal |= Status.Foo;
}
//etc...
}
set
{
IsFoo = value & Status.Foo;
//etc...
}
}
}
精彩评论