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) (EDIT: 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; }
}
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);
}
}
The Selector
class is paired with a template Selector.cshtml
that has some logic to figure out which to pick (radiobutton, checkboxes, etc.).
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>
error:
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>
error:
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>
error:
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 ]
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]'.
Any thoughts on how to use enum
's in this scenario when trying to insert multiple selected enum
s using NHibernate?