NHibernate:枚举以列出并将值存储在数据库中 [英] NHibernate: Enum to list and store values in database
问题描述
我正在使用enum
和自定义的Selector
类来帮助在单选按钮,下拉菜单,复选框等之间进行选择.我正在使用NHibernate.通过单选(单选按钮,下拉菜单),来自属性[Display(Name = "[Some Text]")]
的值将被填充到数据库表中(注意:我正在使用扩展名来使用Display(Name)
).但是,对于多个选择(复选框,多列表),我无法弄清楚如何将enum
选择的值添加到数据库中.
I am using enum
's and a custom Selector
class to help choose between radiobuttons, dropdowns, checkboxes, etc. I am using NHibernate. With a single selection (radiobuttons, dropdowns), the value from attribute [Display(Name = "[Some Text]")]
will be populated in the database table (NOTE: I am using an extension to use Display(Name)
). However, with multiple selections (checkboxes, multilist), I cannot figure out how to get the values of the enum
selections into the database.
这是模型的一部分(每个部分都位于单独的文件中)(我给了它们通用名称,以免进一步混淆问题):
Here are parts of my model (each in separate files) ( I gave them generic names so as not to further confuse the issue):
public enum MyEnum
{
[Display(Name = "Text for enum1")]
enum1,
//Left out 2 - 10 for brevity
[Display(Name = "Text for enum10")]
enum10
}
...
public class MyEnumSelectorAttribute : SelectorAttribute
{
public override IEnumerable<SelectListItem> GetItems()
{
return Selector.GetItemsFromEnum<MyEnum>();
}
}
...
[Display(Name = "This is a checkboxlist (select one or more check boxes)?")]
[MyEnumSelector(BulkSelectionThreshold = 10)]
public virtual List<string> MyEnumCheckBox { get; set; }
...
public List<string> MyEnumCheckBox
{
get { return Record.MyEnumCheckBox; }
set { Record.MyEnumCheckBox = value; }
}
这是Selector.cs
类(在与问题相关的情况下),可帮助选择单选按钮,复选框,下拉菜单等:
And here is the Selector.cs
class (in case it's relevant to the problem) that help's to choose radiobuttons, checkboxes, dropdowns, etc.:
public class Selector
{
public IEnumerable<SelectListItem> Items { get; set; }
public string OptionLabel { get; set; }
public bool AllowMultipleSelection { get; set; }
public int BulkSelectionThreshold { get; set; }
public static string GetEnumDescription(string value, Type enumType)
{
var fi = enumType.GetField(value.ToString());
var display = fi
.GetCustomAttributes(typeof(DisplayAttribute), false)
.OfType<DisplayAttribute>()
.FirstOrDefault();
if (display != null)
{
return display.Name;
}
return value;
}
public static IEnumerable<SelectListItem> GetItemsFromEnum<T>
(T selectedValue = default(T)) where T : struct
{
return from name in Enum.GetNames(typeof(T))
let enumValue = Convert.ToString((T)Enum.Parse
(typeof(T), name, true))
select new SelectListItem
{
Text = GetEnumDescription(name, typeof(T)),
Value = enumValue,
Selected = enumValue.Equals(selectedValue)
};
}
}
public static class SelectorHelper
{
public static IEnumerable<SelectListItem> ToSelectList
(this IEnumerable data)
{
return new SelectList(data);
}
public static IEnumerable<SelectListItem> ToSelectList
(this IEnumerable data, string dataValueField,
string dataTextField)
{
return new SelectList(data, dataValueField, dataTextField);
}
public static IEnumerable<SelectListItem> ToSelectList<T>
(this IEnumerable<T> data, Expression<Func<T, object>>
dataValueFieldSelector, Expression<Func<T, string>>
dataTextFieldSelector)
{
var dataValueField = dataValueFieldSelector.ToPropertyInfo().Name;
var dataTextField = dataTextFieldSelector.ToPropertyInfo().Name;
return ToSelectList(data, dataValueField, dataTextField);
}
}
Selector
类与模板Selector.cshtml
配对,该模板具有一些逻辑以找出要选择的对象(单选按钮,复选框等).
The Selector
class is paired with a template Selector.cshtml
that has some logic to figure out which to pick (radiobutton, checkboxes, etc.).
尝试List<string>
,List<MyEnum>
,IList<string>
,IList<MyEnum>
,IEnumerable<MyEnum>
和IEnumerable<MyEnum>
时遇到各种错误.由于复选框或多重列表使用List<string>
,因此仅会出现此错误.例如,下拉菜单可以正常工作而不会出现错误.这是一个示例下拉模型(可以重复使用上面的enum
),该模型可以工作,并将允许通过NHibernate映射到数据库:
I am getting various errors trying either List<string>
, List<MyEnum>
, IList<string>
, IList<MyEnum>
, IEnumerable<MyEnum>
and IEnumerable<MyEnum>
. This error only comes with checkboxes or multilists since they use List<string>
. Dropdowns, for example, work fine with no errors. Here is a sample dropdown model (can reuse enum
above) that works and will allow mapping to the DB through NHibernate:
[Required(ErrorMessage = "Please select one option")]
[Display(Name = "This is a dropdown list (select one option)?")]
[MyEnumSelector(BulkSelectionThreshold = 0)] //0 selects dropdown
public virtual MyEnum? MyEnumDropDown { get; set; }
public MyEnum? MyEnumDropDown
{
get { return Record.MyEnumDropDown; }
set { Record.MyEnumDropDown = value; }
}
根据我的尝试,这是我遇到的一些错误:
Here are some of the errors I am getting based on what I've tried:
List<string>
错误:
List<string>
error:
NHibernate.Transaction.ITransactionFactory-DTC事务预备阶段失败 NHibernate.PropertyAccessException:无效的类型转换(检查属性类型不匹配的映射); MyNameSpace.Models.MyRecord的设置方法---> System.InvalidCastException:无法转换类型为"NHibernate.Collection.Generic.PersistentGenericBag
1[System.String]' to type 'System.Collections.Generic.List
1 [System.String]"的对象.
NHibernate.Transaction.ITransactionFactory - DTC transaction prepre phase failed NHibernate.PropertyAccessException: Invalid Cast (check your mapping for property type mismatches); setter of MyNameSpace.Models.MyRecord ---> System.InvalidCastException: Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericBag
1[System.String]' to type 'System.Collections.Generic.List
1[System.String]'.
List<MyEnum>
错误:
List<MyEnum>
error:
NHibernate.Transaction.ITransactionFactory-DTC事务预备阶段失败 System.InvalidCastException:无法转换类型为"System.Collections.Generic.List
1[MyNameSpace.Models.MyEnum]' to type 'System.Collections.Generic.ICollection
1 [System.String]"的对象.
NHibernate.Transaction.ITransactionFactory - DTC transaction prepre phase failed System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List
1[MyNameSpace.Models.MyEnum]' to type 'System.Collections.Generic.ICollection
1[System.String]'.
IList<string>
错误:
IList<string>
error:
NHibernate.AdoNet.AbstractBatcher-无法执行命令:INSERT INTO MyEnumCheckBox(MyRecord_id,Value)VALUES(@ p0,@ p1) System.Data.SqlServerCe.SqlCeException(0x80004005):指定的表不存在. [MyEnumCheckBox]
NHibernate.AdoNet.AbstractBatcher - Could not execute command: INSERT INTO MyEnumCheckBox (MyRecord_id, Value) VALUES (@p0, @p1) System.Data.SqlServerCe.SqlCeException (0x80004005): The specified table does not exist. [ MyEnumCheckBox ]
我尝试的其他变体是类似的错误,除了如果使用<MyEnum>
会显示如下错误:
The other variations I tried were similar errors, except that if I used <MyEnum>
it would show an error like this:
System.Collections.Generic.List
1[MyNameSpace.Models.MyEnum]' to type 'System.Collections.Generic.ICollection
1 [System.String]'.
System.Collections.Generic.List
1[MyNameSpace.Models.MyEnum]' to type 'System.Collections.Generic.ICollection
1[System.String]'.
在尝试使用NHibernate插入多个选定的enum
时,在这种情况下如何使用enum
的想法?
Any thoughts on how to use enum
's in this scenario when trying to insert multiple selected enum
s using NHibernate?
推荐答案
由于在Nhibernate中默认情况下使用列表用于单独的表,因此必须使用映射函数将数据库中的单个值映射到列表模型中的值.
Since using lists is used for separate tables by default in Nhibernate, you'll have to use a mapping functions to map a single value from the database to a list of values in your model.
I've demonstrated how to do it here with a working sample, but I'll sum it up once more on your question.
根据您的问题,有2种主要的映射函数类型.他们俩都包括你:
There are 2 major mapping function types based on your problem. They both include that you:
- 将
MyEnumSelector
属性从Record
类移动到模型类, - 更改
Record
的MyEnumCheckBox
属性和 的类型
- 更改模型的
MyEnumCheckBox
属性,以使其与Record
的MyEnumCheckBox
属性相互映射
- move your
MyEnumSelector
attribute from theRecord
class to your model class, - change the type of your
Record
'sMyEnumCheckBox
property and - change your model's
MyEnumCheckBox
property so that it maps to and from yourRecord
'sMyEnumCheckBox
property
所以这些映射函数是:
-
int
到List<MyEnumSelector>
-这是我在链接文章中显示的相同技术.它包括用[Flags]
属性标记您的MyEnumSelector
枚举,并将其项设置为具有2的后续幂的值.您的Record
的MyEnumCheckBox
属性的类型应为int
.然后,映射部分涉及将Record
的MyEnumCheckBox
属性的位与对应的MyEnumSelector
值列表进行映射 -
string
到List<MyEnumSelector>
-这涉及将Record
的MyEnumCheckBox
属性设置为string
类型.然后,映射部分涉及将Record
的MyEnumCheckBox
属性的定界字符串映射到对应的MyEnumSelector
值列表中或从中映射.分隔符可以是逗号,分号或其他字符,您不会将其用作MyEnumSelector
项目值的名称.
int
toList<MyEnumSelector>
- this is the same technique I've shown in the linking post. It includes marking yourMyEnumSelector
enum with the[Flags]
attribute and setting it's items to be of values of subsequent powers of 2. YourRecord
'sMyEnumCheckBox
property should be of typeint
. The mapping part then involves mapping the bits of theRecord
'sMyEnumCheckBox
property to and from the list of correspondingMyEnumSelector
valuesstring
toList<MyEnumSelector>
- this involves setting yourRecord
'sMyEnumCheckBox
property to be of typestring
. The mapping part then involves mapping the delimited string of theRecord
'sMyEnumCheckBox
property to and from the list of correspondingMyEnumSelector
values. Delimiter could be comma or semicolon or some other character that you won't use as a name of yourMyEnumSelector
item values.
这两种方法的主要区别是:
Major differences of these 2 approaches are:
- 枚举大小-使用
int
作为数据库类型时,您只能使用32位数据.这意味着枚举中不能包含超过32个项目.String
没有这种限制 - 易于在数据库中搜索特定值-使用
int
时,您必须处理按位操作的数据库运算符,这些运算符非常混乱并且不那么容易使用,而您可以使用简单的LIKE
string
映射 时的运算符
- 数据库中使用的大小-
int
始终使用4个字节(32位),而string
映射仅对字符串内的一个字符使用该数量(32位)(如果类型为char
,varchar
或text
,并且使用nchar
,nvarchar
或ntext
时大小加倍-64位),因此它将为数据库中的每一行使用更多空间 - 映射速度-
int
映射中使用的按位映射相当快,而string
映射使用的字符串处理函数要慢得多.但是,如果要处理少量数据,这应该不是问题.但是,如果您要处理大量数据,这可能是个大问题.
- Enum size - when using
int
as your database type your're limited to 32 bits of data. This means that you can't have more than 32 items in your enum.String
s don't have this kind of limitation - Ease of searching the database for specific values - when using
int
, you'll have to deal with bit-wise database operators which are quite messy and not that easy to work with, while you could use simpleLIKE
operator when usingstring
mapping - Size used in database -
int
uses always 4 bytes (32-bits) whilestring
mapping uses that amount (32-bits) for only one character inside the string (if it's of typechar
,varchar
ortext
, and double the size - 64-bits when usingnchar
,nvarchar
orntext
) so it will use much more space for each row in the database - Speed of mapping - bit-wise mapping used in
int
mapping is quite fast whilestring
mapping uses string manipulation functions which are much slower. This shouldn't be the problem though if you're dealing with a small amount of data. But if you're going to deal with a massive amount of data this could be a huge issue.
这篇关于NHibernate:枚举以列出并将值存储在数据库中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!