我正在使用enum
和自定义Selector
类来帮助选择radiobuttons,下拉列表,复选框等。我正在使用NHibernate。使用单个选项(单选按钮,下拉列表),属性[Display(Name = "[Some Text]")]
中的值将填充在数据库表中(注意:我使用扩展名来使用Display(Name)
)。但是,通过多个选择(复选框,多列表),我无法弄清楚如何将enum
选择的值放入数据库中。
以下是我的模型的一部分(每个都在单独的文件中)(编辑:我给了他们通用名称,以免进一步混淆问题):
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
类(如果它与问题相关)有助于选择单选按钮,复选框,下拉列表等:
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
配对,模板List<string>
有一些逻辑可以找出要选择的内容(单选按钮,复选框等)。
我在尝试List<MyEnum>
,IList<string>
,IList<MyEnum>
,IEnumerable<MyEnum>
,IEnumerable<MyEnum>
和List<string>
时遇到各种错误。此错误仅附带复选框或多列表,因为它们使用enum
。例如,下拉列表工作正常,没有错误。下面是一个示例下拉模型(可以重用上面的[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; }
}
),它可以通过NHibernate映射到数据库:
List<string>
根据我的尝试,以下是我得到的一些错误:
1[System.String]' to type 'System.Collections.Generic.List
错误:
NHibernate.Transaction.ITransactionFactory - DTC事务预处理阶段失败 NHibernate.PropertyAccessException:无效的Cast(检查映射是否存在属性类型不匹配); MyNameSpace.Models.MyRecord的设定者---&gt; System.InvalidCastException:无法转换类型为'NHibernate.Collection.Generic.PersistentGenericBag
List<MyEnum>
1 [System.String]'的对象。
1[MyNameSpace.Models.MyEnum]' to type 'System.Collections.Generic.ICollection
错误:
NHibernate.Transaction.ITransactionFactory - DTC事务预处理阶段失败 System.InvalidCastException:无法转换类型为'System.Collections.Generic.List
IList<string>
1 [System.String]'的对象。
<MyEnum>
错误:
NHibernate.AdoNet.AbstractBatcher - 无法执行命令:INSERT INTO MyEnumCheckBox(MyRecord_id,Value)VALUES(@ p0,@ p1) System.Data.SqlServerCe.SqlCeException(0x80004005):指定的表不存在。 [MyEnumCheckBox]
我尝试的其他变体是类似的错误,但如果我使用1[MyNameSpace.Models.MyEnum]' to type 'System.Collections.Generic.ICollection
它会显示如下错误:
System.Collections.Generic.List
enum
1 [System.String]”。
在尝试使用NHibernate插入多个选定的enum
时,有关如何在此方案中使用{{1}}的任何想法?
答案 0 :(得分:4)
由于默认情况下在Nhibernate中使用列表用于单独的表,因此您必须使用映射函数将数据库中的单个值映射到模型中的值列表。
我已经演示了如何使用工作示例here,但我会再次总结你的问题。
根据您的问题,有两种主要的映射函数类型。他们都包括你:
MyEnumSelector
属性从Record
类移至模型类Record
的{{1}}媒体资源和MyEnumCheckBox
媒体资源,以便与MyEnumCheckBox
的{{1}}媒体资源进行映射所以那些映射函数是:
Record
到MyEnumCheckBox
- 这与我在链接帖子中显示的技术相同。它包括使用int
属性标记您的List<MyEnumSelector>
枚举,并将其项目设置为后续幂2的值。您的MyEnumSelector
的{{1}}属性应为类型[Flags]
。映射部分然后涉及将Record
的{{1}}属性的位映射到相应的MyEnumCheckBox
值列表中int
至Record
- 这涉及将MyEnumCheckBox
的{{1}}属性设置为MyEnumSelector
类型。然后,映射部分涉及将string
的{{1}}属性的分隔字符串映射到相应的List<MyEnumSelector>
值列表中。分隔符可以是逗号或分号或其他一些您不会用作Record
项值的名称的字符。这两种方法的主要区别是:
MyEnumCheckBox
作为数据库类型时,限制为32位数据。这意味着您的枚举中不能包含超过32个项目。 string
没有这种限制Record
时,您将不得不处理那些非常混乱并且不易于使用的逐位数据库运算符,而您可以使用简单{使用MyEnumCheckBox
映射MyEnumSelector
始终使用4个字节(32位),而MyEnumSelector
映射仅对字符串中的一个字符使用该数量(32位)(如果它的类型为{ {1}},int
或String
,并且在使用int
,LIKE
或string
时大小加倍 - 64位,因此会使用很多数据库中每行的空间更多int
映射中使用的逐位映射非常快,而string
映射使用速度慢得多的字符串操作函数。如果您处理少量数据,这应该不是问题。但是,如果你要处理大量数据,这可能是个大问题。答案 1 :(得分:1)
我会将复选框值设为枚举的int值。
一些建议:
答案 2 :(得分:0)
PersistentGenericBag绝对不是List&lt; string&gt;,但它确实实现了IList&lt; string&gt;:
public class PersistentGenericBag<T> : PersistentBag, IList<T>
使用IList&lt; string&gt;时相反,你确定从代码中的相同位置得到完全相同的错误吗?