REM*_*ESQ 2 nhibernate asp.net-mvc orchardcms
我一生都无法将它与我现有的代码一起使用,但我正在尝试将我的enum选择保存为 NHibernate 中的字符串。基本上,我有一个 UI 复选框,如果用户选择多个复选框,我想存储这些选择。现在,我可以让 NHibernate 存储一个选择(例如,从下拉列表或单选按钮列表中,用户仅限于一个选择)。
这是我对枚举的jist:
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
}
Run Code Online (Sandbox Code Playgroud)
我使用一种方法来“选择”是否显示复选框列表(如果我BulkItemThreshold的选项数量等于选项数,则显示一个复选框列表)。这是那个方法:
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)
};
}
Run Code Online (Sandbox Code Playgroud)
(注意:其中的某些项目有帮助程序,但我认为它们不相关;此外,所选输入是使用模板.cshtml文件显示的- 同样,不确定这是否相关)
现在,我这样称呼它:
public class IncomeTypeSelectorAttribute : SelectorAttribute
{
public override IEnumerable<SelectListItem> GetItems()
{
return Selector.GetItemsFromEnumString<IncomeType>();
}
}
Run Code Online (Sandbox Code Playgroud)
最后,我们到达了virtual属性(使用代理),但这是 NHibernate 抛出一个扳手的地方(注意:这在 NHibernate 之前对我来说很好用,现在我试图让很多代码行使用它而不必重新做所有事情;如果我重新做所有事情,我可能会将我已经需要让它工作的代码增加三倍):
属性(记录):
[IncomeTypeSelector(BulkSelectionThreshold = 9)]
public virtual List<string> IndividualIncomeTypeCheckBox { get; set; }
Run Code Online (Sandbox Code Playgroud)
代理(部分):
public List<string> IndividualIncomeTypeCheckBox
{
get { return Record.IndividualIncomeTypeCheckBox; }
set { Record.IndividualIncomeTypeCheckBox = value; }
}
Run Code Online (Sandbox Code Playgroud)
同样,这就是我做事的方式,在 NHibernate 之前它运行良好。但现在我必须使用 NHibernate。没有绕过它。
我正在使用一个服务类,它在 Create 方法中将两者联系在一起,以使用 NHibernate 保存在数据库中,对于上面的内容,它通常如下所示:
part.IndividualIncomeTypeCheckBox = record.IndividualIncomeTypeCheckBox;
Run Code Online (Sandbox Code Playgroud)
如果它只是一种选择,这将起作用。
好吧,我已经花了两 (2) 个月的时间试图让它发挥作用。这很困难,因为我有很多代码,用户只能在其中进行一个选择(例如使用单选按钮列表),并且它运行良好 - 即使使用 NHibernate。让我给你举个例子:
public virtual IncomeType? IndividualIncomeTypeCheckBox { get; set; }
Run Code Online (Sandbox Code Playgroud)
如果我执行上述操作,它将显示一个下拉列表,NHibernate 会将用户选择的 ONE 允许选项存储在数据库中,没问题。但不止一个选项 withList<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; }
}
Run Code Online (Sandbox Code Playgroud)
这会显示在 UI 上,但我尝试用 NHibernate 做类似的事情,但它不起作用。
任何人都可以告诉我,使用上面的内容,我如何才能让 NHibernateenum在这个复选框列表场景中存储多个?
更新: 更多地在这里和网上闲逛,我想出了以下内容(仍然不起作用)。
属性(记录):
[IncomeTypeSelector(BulkSelectionThreshold = 9)]
public virtual IList<IncomeTypeRecord> IndividualIncomeTypeCheckBox
{
get { return incomeType; }
set { incomeType= value; }
}
private IList<IncomeTypeRecord> incomeType =
new List<IncomeTypeRecord>();
Run Code Online (Sandbox Code Playgroud)
代理(部分):
public IList<IncomeTypeRecord> IndividualIncomeTypeCheckBox
{
get { return Record.IndividualIncomeTypeCheckBox; }
set { Record.IndividualIncomeTypeCheckBox= value; }
}
Run Code Online (Sandbox Code Playgroud)
以及对枚举的更改:
public enum IncomeType : int // removing int & value still gives validate error
{
[Display(Name = "Full-Time Employment")]
FullTime = 1,
[Display(Name = "Part-Time Employment")]
PartTime,
....
}
Run Code Online (Sandbox Code Playgroud)
我添加了这个类来支持 IncomeTypeRecord
public class IncomeTypeRecord
{
public virtual int Id { get; set; }
public virtual IncomeType Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但是,当我进入 UI 屏幕并选择一个或多个选项时,我收到验证错误(值无效)。例如,假设我单独选择 FullTime,或者选择 FullTime 和 Retirement,那么 UI 将显示以下错误:
值“FullTime”无效。
值“FullTime,Retirement”无效。
(分别)
即使我删除了 的int声明enum并删除了以“1”开头的值,我仍然会收到此验证错误。我尝试使用并添加不同的模型绑定器(这让我不知道我原来的问题是否仍然存在,现在我有一个不同的问题 - 但你仍然得到赏金点:))。
拉我的头发。如果我可以提供更多的赏金,我会的。我需要一个明确的解决方案。我很感激任何帮助。
更新 这是我到目前为止:
记录:
public virtual string IndividualIncomeTypeCheckBox{ get; set; }
Run Code Online (Sandbox Code Playgroud)
部分:
//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); }
}
Run Code Online (Sandbox Code Playgroud)
服务等级:
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;
...
}
Run Code Online (Sandbox Code Playgroud)
这就是它在控制器中的调用方式(这会持续到 DB):(更新控制器代码)
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);
}
Run Code Online (Sandbox Code Playgroud)
更新附加代码(序列化和视图模型):
“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;
}
Run Code Online (Sandbox Code Playgroud)
我使用序列化是因为我在前端设置了一个多步向导(如控制器操作“backButton”“nextButton”中所示)。我没有使用驱动程序(它只能显示 Admin 或在前端但是然后仅在 ~/Views 文件夹下的 .cshtml 文件上(不在我使用的结构化文件夹列表中)。没有驱动程序 = 没有更新视图模型类型代码 = 没有在数据库中“创建”数据的机制。如果我不使用某些“创建”类型的方法,表单将提交但所有数据将为“NULL”。
当你说数据应该自动持久化时,我很抱歉,但我不知道如何。我阅读的所有内容或我查看的代码都有一些使用表单中输入的内容更新数据库的方法。如果我遗漏了什么,我深表歉意。
“MyViewModel”非常简单:
[Serializabel]
public class MyViewModel
{
public SimplePartRecord SimplePartRecord { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
而且,为了以防万一,这里是迁移的相关部分(返回 1 是一个完全独立且不相关的表):
public int UpdateFrom1()
{
SchemaBuilder.CreateTable("SimplePartRecord",
table => table
.ContentPartRecord()
...
.Column("IndividualIncomeTypeCheckBox", DbType.String)
...
);
ContentDefinitionManager.AlterPartDefinition("SimplePart",
part => part
.Attachable(false));
return 2;
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误是
无法将类型 'string' 隐式转换为 'System.Collections.Generic.IEnumerable'"
当我在服务类的“创建”方法中执行以下操作时:
simple.IndividualIncomeTypeCheckBox = record.IndividualIncomeTypeCheckBox;
Run Code Online (Sandbox Code Playgroud)
另一个想法:我尝试使用 nn Relation 示例来处理这种情况。除了它是很多额外的代码,我认为应该是直接和简单的,因为我使用序列化的方式我有很多对象引用错误,无法弄清楚如何正确编码我的控制器来处理它。
这里有很多信息需要浏览,所以希望我没有错过重点。在我看来,目标是:
IList<IncomeType>不需要额外表的集合属性最好的方法是使用自定义用户类型( 的实现NHibernate.UserTypes.IUserType)来映射属性。下面是一个泛型IUserType,它将一个类型的枚举T从IList<T>属性映射到数据库中的逗号分隔字符串,然后再返回。没有简单的方法可以将 T 限制为枚举,但代码仅适用于枚举。
使用 Fluent NHibernate 映射使用自定义类型的属性很简单:
public class Person
{
public Person()
{
IncomeTypes = new List<IncomeType>();
}
public virtual int PersonId { get; protected set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual IList<IncomeType> IncomeTypes { get; protected set; }
}
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Table("Person");
Id(x => x.PersonId).GeneratedBy.Identity();
Map(x => x.FirstName);
Map(x => x.LastName);
Map(x => x.IncomeTypes).CustomType<EnumAsDelimitedStringType<IncomeType>>();
}
}
Run Code Online (Sandbox Code Playgroud)
这是用户类型的代码:
public class EnumAsDelimitedStringType<T> : IUserType
{
public new bool Equals(object x, object y)
{
if (ReferenceEquals(x, y))
{
return true;
}
var xList = x as IList<T>;
var yList = y as IList<T>;
if (xList == null || yList == null)
{
return false;
}
// compare set contents
return xList.OrderBy(xValue => xValue).SequenceEqual(yList.OrderBy(yValue => yValue));
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var outValue = NHibernateUtil.AnsiString.NullSafeGet(rs, names[0]) as string;
if (string.IsNullOrEmpty(outValue))
{
return new List<T>();
}
var getValueArray = outValue.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
return Array.ConvertAll(getValueArray, s => (T)Enum.Parse(typeof(T), s)).ToList();
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var inValue = value as IList<T>;
// set to string.Empty if you prefer to store that instead of null when the collection is null or empty
object setValue = null;
if (inValue != null && inValue.Any())
{
var setValueArray = Array.ConvertAll(inValue.ToArray(), v => Enum.GetName(typeof(T), v));
setValue = string.Join(",", setValueArray);
}
NHibernateUtil.AnsiString.NullSafeSet(cmd, setValue, index);
}
public object DeepCopy(object value)
{
return value;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
public SqlType[] SqlTypes
{
get { return new[] {new SqlType(DbType.AnsiString)}; }
}
public Type ReturnedType
{
get { return typeof(IList<T>); }
}
public bool IsMutable
{
get { return false; }
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1502 次 |
| 最近记录: |