enum MyEnum
with属性を装飾し[Flags]
、その項目の値を 2 の異なる累乗に設定できます。たとえば、列挙型は次のようになります。
[Flags]
public enum MyEnum
{
Enum1 = 1,
Enum2 = 2,
Enum3 = 4,
Enum4 = 8,
Enum5 = 16
}
これで、 クラスMyEnumCheckBox
のプロパティのタイプは次のようになります。PartRecord
int
public virtual int MyEnumCheckBox { get; set; }
Part
クラス内にプロキシ プロパティを作成できます。例えば:
private IList<MyEnum> _myCheckBox;
[MyEnumSelector]
public IList<MyEnum> MyCheckBox
{
get
{
if (_myCheckBox == null)
{
_myCheckBox = new List<MyEnum>();
foreach (MyEnum item in Enum.GetValues(typeof(MyEnum)))
{
if (((MyEnum)Record.MyEnumCheckBox & item) == item)
_myCheckBox.Add(item);
}
}
return _myCheckBox;
}
set
{
_myCheckBox = value;
Record.MyEnumCheckBox = 0;
foreach (var item in value)
{
Record.MyEnumCheckBox |= (int)item;
}
}
}
Flags 属性の詳細については、こちらを参照してください。基本的に、探しているものとまったく同じ単一の列挙フィールドに複数の列挙値を使用できるようにするのに役立ちます。
編集:
私は時間をかけてカスタム モジュールを作成し、この手法を示しました。私はそれをテストしましたが、正常に動作します。だからここにソースがあります:
Migrations.cs
public int Create()
{
SchemaBuilder.CreateTable("MultipleEnumPickerRecord", table => table
.ContentPartRecord()
.Column<int>("SelectedItems"));
ContentDefinitionManager.AlterPartDefinition("MultipleEnumPickerPart", p => p.Attachable());
return 1;
}
モデル:
[Flags]
public enum MyEnum
{
Enum1 = 1, // bit-wise 00001 or 2^0
Enum2 = 2, // bit-wise 00010 or 2^1
Enum3 = 4, // bit-wise 00100 or 2^2
Enum4 = 8, // bit-wise 01000 or 2^3
Enum5 = 16 // bit-wise 10000 or 2^4
}
public class MultipleEnumPickerRecord : ContentPartRecord
{
public virtual int SelectedItems { get; set; }
}
public class MultipleEnumPickerPart : ContentPart<MultipleEnumPickerRecord>
{
private IList<MyEnum> _selectedItems;
public IList<MyEnum> SelectedItems
{
get
{
if (_selectedItems == null)
{
_selectedItems = new List<MyEnum>();
foreach (MyEnum item in Enum.GetValues(typeof(MyEnum)))
{
if (((MyEnum)Record.SelectedItems & item) == item)
_selectedItems.Add(item);
}
}
return _selectedItems;
}
set
{
_selectedItems = value;
Record.SelectedItems = 0;
foreach (var item in value)
{
Record.SelectedItems |= (int)item;
}
}
}
}
ハンドラ:
public class MultipleEnumPickerHandler : ContentHandler
{
public MultipleEnumPickerHandler(IRepository<MultipleEnumPickerRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
}
}
運転者:
public class MultipleEnumPickerDriver : ContentPartDriver<MultipleEnumPickerPart>
{
protected override string Prefix { get { return "MultipleEnumPicker"; } }
protected override DriverResult Editor(MultipleEnumPickerPart part, dynamic shapeHelper)
{
return ContentShape("Parts_MultipleEnumPicker_Edit", () => shapeHelper.EditorTemplate(
TemplateName: "Parts/MultipleEnumPicker", Model: part, Prefix: Prefix));
}
protected override DriverResult Editor(MultipleEnumPickerPart part, IUpdateModel updater,
dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
配置:
<Placement>
<Place Parts_MultipleEnumPicker_Edit="Content:5"/>
</Placement>
最後に、ビュー:
@using ModuleNamespace.Models
@model MultipleEnumPickerPart
<fieldset>
<div class="editor-label">@Html.LabelFor(x => x.SelectedItems)</div>
<div class="editor-field">
<select multiple="multiple" id="@Html.FieldIdFor(x => x.SelectedItems)" name="@Html.FieldNameFor(x => x.SelectedItems)">
@foreach (MyEnum item in Enum.GetValues(typeof(MyEnum))) {
var selected = Model.SelectedItems.Contains(item);
<option value="@((int)item)" @if(selected) {<text>selected="selected"</text>}>
@T(item.ToString())
</option>
}
</select>
</div>
</fieldset>
ただし、この手法を実装する際には、次の 2 つの点に注意する必要があります。
- 列挙型は内部的に整数として扱われます。つまり、それらの値は 32 ビットを占めます。
MyEnum
これは、これが機能するために 32 を超える列挙項目を定義できないことを意味します。
- Bertrand が指摘したように、アイテムのデータベース検索は難しくなります (ただし、主要なデータベースではビット単位の演算子を使用できるため、不可能ではありません)。
これらの両方の制約は、データベースとモデルの間で異なるマッピング関数を使用することでバイパスできます。
どういう意味ですか?
私が示した例では、データベースの値 (およびMultipleEnumPickerRecord
値) は型ですが、int
そのMultipleEnumPickerPart
整数を に「マップ」しましたList<MyEnum>
。これにより、データベース内のスペースが少なくなり、他のマッピング関数を使用するよりも高速になります。
たとえば、string
データベースのタイプを使用してから、 の内部にMultipleEnumPickerRecord
何らかのマッピングを行うことができます。最も一般的な文字列マッピング関数はList<MyEnum>
MultipleEnumPickerPart
- カンマ区切りのマッピング - たとえば、誰かが and を選択
Enum1
しEnum4
た場合、それを文字列にマッピングできます"Enum1,Enum4"
- セミコロン区切りのマッピング - 前の例を次のようにマッピングします
"Enum1;Enum4"
選択する区切り文字のタイプは、文字列で使用しないことがわかっている文字に基づいている必要があります。データベース内の文字列からリストを分解するには、単純なものを使用できますvalue.Split(',').ToList();
(区切り文字として「,」を使用している場合)。
この方法では、32 個の列挙項目だけに制限されることはありません。また、値が文字列として保存されるため、データベースで値を検索するのは非常に簡単です。欠点は、文字列がデータベース内でより多くのスペースを必要とし (int は文字列から 1 文字のスペースを占有します)、文字列操作関数は上記のサンプルで示したビット単位の関数よりも多少遅くなります。