我一辈子都无法让它与我现有的代码一起使用,但我正在尝试将我的enum
选择保存为 NHibernate 中的字符串。基本上,我有一个 UI 复选框,如果用户选择多个复选框,我想存储这些选择。现在,我可以让 NHibernate 存储一个选择(例如,从下拉列表或单选按钮列表中,用户仅限于一个选择)。
这是我对枚举的主要内容:
public enum IncomeType
{
[Display(Name = "Full-Time Employment")]
FullTime,
[Display(Name = "Part-Time Employment")]
PartTime,
[Display(Name = "Self-Employment")]
SelfEmployed,
[Display(Name = "Rental")]
Rental,
[Display(Name = "Social Security Payments")]
SocialSecurity,
[Display(Name = "Retirement / Pension Payments")]
Retirement,
[Display(Name = "Child Support Payments")]
ChildSupport,
[Display(Name = "Spousal Maintenance")]
Maintenance,
[Display(Name = "Other")]
Other
}
我使用一种方法来“选择”是否显示复选框列表(如果 myBulkItemThreshold
等于选项数,则显示复选框列表)。这是那个方法:
public static IEnumerable<SelectListItem> GetItemsFromEnumString<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)
};
}
(注意:其中的一些项目是助手,但我认为它们不相关;此外,所选输入使用模板.cshtml
文件显示 - 再次,不确定这是否相关)
现在,我这样称呼它:
public class IncomeTypeSelectorAttribute : SelectorAttribute
{
public override IEnumerable<SelectListItem> GetItems()
{
return Selector.GetItemsFromEnumString<IncomeType>();
}
}
最后,我们到达了virtual
属性(使用代理),但这是 NHibernate 抛出扳手的地方(注意:在 NHibernate 之前这对我来说工作得很好,现在我试图让许多代码行使用它而不必重新做所有事情;如果我重新做所有事情,我可能会将我已经必须让它工作的代码增加三倍):
财产(记录):
[IncomeTypeSelector(BulkSelectionThreshold = 9)]
public virtual List<string> IndividualIncomeTypeCheckBox { get; set; }
代理(部分):
public List<string> IndividualIncomeTypeCheckBox
{
get { return Record.IndividualIncomeTypeCheckBox; }
set { Record.IndividualIncomeTypeCheckBox = value; }
}
同样,这就是我做事的方式,并且在 NHibernate 之前它工作得很好。但现在我必须使用 NHibernate。没有绕过它。
我正在使用一个服务类,它将两者结合在一个 Create 方法中,以使用 NHibernate 保存在数据库中,对于上面的内容,它通常看起来像这样:
part.IndividualIncomeTypeCheckBox = record.IndividualIncomeTypeCheckBox;
如果它只是一个选择,这将起作用。
好吧,我花了整整两 (2) 个月的时间试图让它发挥作用。这很困难,因为我有很多代码,用户只能做出一个选择(例如使用单选按钮列表),而且效果很好——即使使用 NHibernate。让我给你举个例子:
public virtual IncomeType? IndividualIncomeTypeCheckBox { get; set; }
如果我执行上述操作,它将显示一个下拉列表,NHibernate 会将用户选择的 ONE 允许选项存储在数据库中,这没有问题。但是一个以上的选项List<string>
不起作用。
现在,我已经尝试了在这里或其他地方能找到的一切,但没有任何效果。是的,我知道它应该是IList<IncomeType>
或其他一些变体。但是如果我使用它,那么 NHibernate 需要它IncomeType
是数据库中的另一个表。对于我相信的这么简单的事情,编写的代码太多了。我们不是在谈论多对多关系,因为这不是具有多个地址的用户(其中地址将具有街道、城市、州、邮政编码等)。
我尝试了不同类型的代理get
和set
代码,但没有任何效果。我已经尝试过[Flags]
和其他东西一起工作string
,但无济于事。那些最后的解决方案将“工作”,但只能保存从多个中选择的第一个项目(即,在我的场景中,如果用户选择“FullTime”和“Rental”作为收入类型,那么只会string
保存“FullTime”()或“1”([Flags]
/ int
),而不是两个项目都被选中。
ReadOnly
我有一种情况,我使用这样的属性重新显示选择:
[IncomeTypeSelector]
[ReadOnly(true)]
public List<string> IndividualIncomeTypeCheckBoxPost
{
get { return IndividualIncomeTypeCheckBox; }
}
这将显示在 UI 上,但我尝试用 NHibernate 做这样的事情,但它不起作用。
enum
谁能告诉我,使用上面的内容,我怎样才能让 NHibernate在这个复选框列表场景中存储多个?
更新: 更多在这里和网络上戳,我想出了以下(仍然不起作用)。
财产(记录):
[IncomeTypeSelector(BulkSelectionThreshold = 9)]
public virtual IList<IncomeTypeRecord> IndividualIncomeTypeCheckBox
{
get { return incomeType; }
set { incomeType= value; }
}
private IList<IncomeTypeRecord> incomeType =
new List<IncomeTypeRecord>();
代理(部分):
public IList<IncomeTypeRecord> IndividualIncomeTypeCheckBox
{
get { return Record.IndividualIncomeTypeCheckBox; }
set { Record.IndividualIncomeTypeCheckBox= value; }
}
以及对枚举的更改:
public enum IncomeType : int // removing int & value still gives validate error
{
[Display(Name = "Full-Time Employment")]
FullTime = 1,
[Display(Name = "Part-Time Employment")]
PartTime,
....
}
我添加了这个类来支持IncomeTypeRecord
public class IncomeTypeRecord
{
public virtual int Id { get; set; }
public virtual IncomeType Value { get; set; }
}
但是,当我进入 UI 屏幕并选择一个或多个选项时,我收到验证错误(值无效)。例如,假设我单独选择 FullTime,或者选择 FullTime 和 Retirement,那么 UI 将显示以下错误:
'FullTime' 值无效。
'FullTime,Retirement' 值无效。
(分别)
即使我删除了int
声明enum
并摆脱了以“1”开头的值,我仍然会收到此验证错误。我尝试弄乱并添加不同的模型活页夹(现在让我很难过我原来的问题是否仍然存在,现在我有一个不同的问题 - 但你仍然可以获得赏金:))。
把我的头发拉出来。如果我能提供更多的赏金,我会的。我需要一个明确的解决方案。我很感激任何帮助。
更新 这是我到目前为止所拥有的:
记录:
public virtual string IndividualIncomeTypeCheckBox{ get; set; }
部分:
//If I do IEnumberable<string> my .Select throws a cast error
public IEnumerable<IncomeType> IndividualIncomeTypeCheckBox
{
get
{
return Record
.IndividualIncomeTypeCheckBox
.Split(',')
.Select(r => (IncomeType)Enum.Parse(typeof(IncomeType), r));
}
set { Record.IndividualIncomeTypeCheckBox= value
== null ? null : String.Join(",", value); }
}
服务等级:
public SimplePart CreateSimple(SimplePartRecord record)
{
SimplePart simple = Services.ContentManager.Create<SimplePart>("Simple");
...
//How I would save a FirstName property (example Part / PartRecord below)
//public virtual string FirstName { get; set; } - PartRecord
//public string FirstName - Part
//{
// get { return Record.FirstName ; }
// set { Record.FirstName= value; }
//}
simple.FirstName = record.FristName;
...
//I obviously cannot do the following with the above IncomeType
//Getting cannot convert string to IEnumerable error
//How would I write this:
simple.IndividualIncomeTypeCheckBox = record.IndividualIncomeTypeCheckBox;
...
}
这就是它在控制器中的调用方式(这持续到数据库):(更新控制器代码)
public ActionResult Confirm(string backButton, string nextButton)
{
if (backButton != null)
return RedirectToAction("WrapUp");
else if ((nextButton != null) && ModelState.IsValid)
{
_myService.CreateSimple(myData.SimplePartRecord);
return RedirectToAction("Submitted");
}
else
return View(myData);
}
更新附加代码(序列化和视图模型):
“myData”在控制器(使用序列化)中定义为:
private MyViewModel myData;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var serialized = Request.Form["myData"];
if (serialized != null)
{
myData = (MyViewModel)new MvcSerializer().Deserialize
(serialized, SerializationMode.Signed);
TryUpdateModel(myData);
}
else
myData = (MyViewModel)TempData["myData"] ?? new MyViewModel();
TempData.Keep();
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["myData"] = myData;
}
我使用序列化是因为我在前端设置了一个多步骤向导(如控制器操作“backButton”“nextButton”中所示)。我没有使用驱动程序(只能显示 Admin 或在前端但然后仅在 ~/Views 文件夹下的 .cshtml 文件上(而不是像我正在使用的结构化文件夹列表中)。没有驱动程序 = 没有更新视图模型类型代码 = 没有在数据库中“创建”数据的机制。如果我不使用一些“创建”类型的方法,表单会提交,但所有数据都是“NULL”。
当您说数据应该自动持久化时,我很抱歉,但我不知道如何。我阅读的所有内容或我查看的代码都有一些方法可以使用表单中输入的任何内容来更新数据库。如果我遗漏了什么,我很抱歉。
“MyViewModel”非常简单:
[Serializabel]
public class MyViewModel
{
public SimplePartRecord SimplePartRecord { get; set; }
}
而且,以防万一,这里是迁移的相关部分(返回 1 是一个完全独立且不相关的表):
public int UpdateFrom1()
{
SchemaBuilder.CreateTable("SimplePartRecord",
table => table
.ContentPartRecord()
...
.Column("IndividualIncomeTypeCheckBox", DbType.String)
...
);
ContentDefinitionManager.AlterPartDefinition("SimplePart",
part => part
.Attachable(false));
return 2;
}
我得到的错误是
无法将类型“字符串”隐式转换为“System.Collections.Generic.IEnumerable””
当我在我的服务类的“创建”方法中执行以下操作时:
simple.IndividualIncomeTypeCheckBox = record.IndividualIncomeTypeCheckBox;
另一个想法:我尝试使用 nn Relation 示例来处理这种情况。除了我认为应该简单明了的大量额外代码之外,由于我使用序列化的方式,我有很多对象引用错误,并且无法弄清楚如何正确编码我的控制器来处理它。