2012-12-06 47 views
2

我使用enum的和自定義Selector類來幫助選擇單選按鈕,下拉列表,複選框等我使用的是NHibernate。通過單個選項(單選按鈕,下拉列表),來自屬性[Display(Name = "[Some Text]")]的值將填充到數據庫表中(注意:我正在使用擴展名以使用Display(Name))。但是,通過多選(複選框,多列表),我無法弄清楚如何將enum選擇的值存入數據庫。NHibernate:枚舉列出和存儲數據庫中的值

這裏是我的模型的部分(每個單獨的文件)(編輯:我給他們的通用名稱,以免進一步混淆問題):

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)的作品,並允許通過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; } 
    } 

這裏有一些我基於什麼我已經試過得到錯誤的:

List<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>錯誤:

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>錯誤:

System.Collections.Generic.List 1[MyNameSpace.Models.MyEnum]' to type 'System.Collections.Generic.ICollection 1[System.String]'.

任何想法:

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>它會顯示這樣的錯誤的其他變化在嘗試使用NHibernate插入多個選定的enum時如何在此場景中使用enum

回答

4

由於使用列表中默認Nhibernate的用於單獨的表的局部視圖,你將不得不使用一個映射函數來映射從數據庫中的單個值到模型中的值列表。

我已經演示瞭如何做here帶有一個工作示例,但我會再次總結一下您的問題。

根據您的問題,有2種主要的映射函數類型。他們都包括您:

  1. Record類的MyEnumSelector屬性轉移到你的模型類,
  2. 變化的類型你RecordMyEnumCheckBox財產和
  3. 變化模型的MyEnumCheckBox屬性,使之地圖,並從您RecordMyEnumCheckBox財產

因此,這些映射函數是:

  1. intList<MyEnumSelector> - 這是我在鏈接帖子中顯示的相同技巧。它包括標記MyEnumSelector enum與[Flags]屬性並將它的項目設置爲後續冪值爲2.您的RecordMyEnumCheckBox屬性應爲int類型。映射部分則涉及Record的位映射的MyEnumCheckBox屬性和相應的MyEnumSelector
  2. stringList<MyEnumSelector>名單 - 這包括了設置您的RecordMyEnumCheckBox屬性爲string型。然後映射部分涉及將Record的屬性的分隔字符串映射到對應的MyEnumSelector值的列表和從對應的MyEnumSelector值的列表映射。分隔符可以是逗號或分號,也可以是其他不會用作您的MyEnumSelector項值的名稱的其他字符。

的這些2種方法的主要區別是:

  1. 枚舉大小 - 使用int作爲數據庫類型your're限制爲32位數據時。這意味着您的枚舉中不能有超過32個項目。String s沒有這種限制
  2. 在數據庫中搜索特定值的易用性 - 使用int時,您必須處理比特數據庫操作符,這些操作符相當混亂且不易處理,雖然你可以使用string映射時使用簡單LIKE操作
  3. 在數據庫中使用尺寸 - int總是使用4個字節(32位),而string映射將使用量(32位)的字符串內只有一個字符(如果它是類型爲charvarchartext,大小加倍 - 使用時爲64位 - ncharnvarcharntext ),因此它將爲數據庫中的每一行使用更多空間。
  4. 映射速度 - 在int映射中使用的按位映射非常快,而string映射使用速度慢得多的字符串操作函數。如果你正在處理少量的數據,這應該不是問題。但是如果你要處理大量的數據,這可能是一個巨大的問題。
0

PersistentGenericBag絕對不是一個列表<串>,但它確實實現IList <串>:

public class PersistentGenericBag<T> : PersistentBag, IList<T> 

當您使用的IList <串>相反,你確定你在得到確切的同樣的錯誤代碼中的同一個地方?

+0

不,我得到一個不同的錯誤。我做了至少六(6)個變化,這是最初的錯誤。我認爲我得到的一個錯誤是「無法插入集合......指定的表不存在」 –

+0

那麼,由於PersistentGenericBag <>顯然不是List <>,因此應該忘記該錯誤。嘗試使用例如IList <>代替。這種情況下的完整錯誤信息更有趣。 –

+0

感謝您的回覆。對不起,如果我誤解:你是否希望我在使用IList <>'的情況下發布錯誤信息?問題是,我使用IList 或IList <[我的枚舉名稱]>'? –

1

我會使複選框值爲枚舉的int值。

幾點建議:

  • 使用System.DayOfWeek枚舉代替你自己的枚舉。
  • 枚舉可以映射爲NHibernate中的自定義類型。
  • 由於星期幾是一個單詞,因此不需要顯示屬性。控件值應該是枚舉的int值(可以直接投射)。
  • 使用對於不同的控制集合(下拉,收音機等)
+0

關於'System.DayOfWeek'和使用'Display'屬性的好處。但是,這只是一個例子。我正在對所有輸入重用'enum'和'Selector'範例。我有很多其他複選框。我希望不必爲了複選框而改變它。例如,我有一個收入類型複選框(全部,部分,自僱等)。 –

相關問題