I can't make this work for my whole life with my existing code, but I'm trying to save my enum selections as strings in NHibernate. Basically, I have a user interface, and if the user selects several checkboxes, I want to save these options. Now I can get NHibernate to store the ONE selection (for example, from a drop-down list or a list of radio buttons where the user is limited to only one choice).
This is the essence of what I have for listing:
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 }
I use the method to "select" whether a list of flags is displayed (if my BulkItemThreshold is equal to the number of options, a list of flags is displayed). Here is the method:
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) }; }
(Note: some elements have helpers, but I do not think they are relevant, and the selected input is displayed using the .cshtml file template - again, not sure if this is relevant)
Now I call it like this:
public class IncomeTypeSelectorAttribute : SelectorAttribute { public override IEnumerable<SelectListItem> GetItems() { return Selector.GetItemsFromEnumString<IncomeType>(); } }
And finally, we get to the virtual property (using a proxy), but this is where NHibernate throws the key (Note: this worked fine for me before NHibernate, and now I'm trying to get many lines of code working with it WITHOUT having to repeat everything if I will do everything again that I will probably triple the code that I already need to make it work):
Property (record):
[IncomeTypeSelector(BulkSelectionThreshold = 9)] public virtual List<string> IndividualIncomeTypeCheckBox { get; set; }
proxy (part):
public List<string> IndividualIncomeTypeCheckBox { get { return Record.IndividualIncomeTypeCheckBox; } set { Record.IndividualIncomeTypeCheckBox = value; } }
Again, this is what I did, and it worked perfectly up to NHibernate. But now I have to use NHibernate. Do not get around this.
I use a service class that binds them together in the Create method to save to the database using NHibernate, and for the above, this usually looks like this:
part.IndividualIncomeTypeCheckBox = record.IndividualIncomeTypeCheckBox;
This will work if it is just one choice.
Well, I spent two (two) months trying to get this to work. This is complicated because I have a lot of code where the user can only make one choice (for example, with a list of radio books), and it works GREAT - even with NHibernate. Let me give you an example:
public virtual IncomeType? IndividualIncomeTypeCheckBox { get; set; }
If I do this above, a drop-down list will be displayed, and NHibernate will save the ONE function selected by the user, selected by the user in the database, without problems. But more than one option with List<string> does not work.
Now I tried everything that I could find here or somewhere else, and nothing works. Yes, I know that it should be IList<IncomeType> or some other option. But if I use this, then NHibernate requires IncomeType be another table in the database. This is too much code to write such a simple thing as I think. We are not talking about the many-to-many relationship in the sense that this is not a user with multiple addresses (in which the addresses would have a street, city, state, zip code, etc.).
I tried different types of get and set proxy code, but nothing works. I tried [Flags] and other things that work only with string , but to no avail. These last solutions will "work", but ONLY to save the first item selected from several (i.e., in my scenario, if the user selects "FullTime" and "Rental" as income types, then only "FullTime" ( string ) will be saved or "1" ( [Flags] / int ), not both selected items.
I have a situation where I am re-viewing options using the ReadOnly attribute as follows:
[IncomeTypeSelector] [ReadOnly(true)] public List<string> IndividualIncomeTypeCheckBoxPost { get { return IndividualIncomeTypeCheckBox; } }
This will display in the user interface, but I tried to do something similar with NHibernate, and it will not work.
Can someone show me, using the above, how can I get NHibernate to store more than one enum in this checkbox list script?
UPDATE: Noisier here and on the Internet, and I came up with the following (which still doesn't work).
Property (record):
[IncomeTypeSelector(BulkSelectionThreshold = 9)] public virtual IList<IncomeTypeRecord> IndividualIncomeTypeCheckBox { get { return incomeType; } set { incomeType= value; } } private IList<IncomeTypeRecord> incomeType = new List<IncomeTypeRecord>();
Proxy (part):
public IList<IncomeTypeRecord> IndividualIncomeTypeCheckBox { get { return Record.IndividualIncomeTypeCheckBox; } set { Record.IndividualIncomeTypeCheckBox= value; } }
And the change of listing:
public enum IncomeType : int
And I added this class to support IncomeTypeRecord
public class IncomeTypeRecord { public virtual int Id { get; set; } public virtual IncomeType Value { get; set; } }
HOWEVER, when I get to the user interface screen and select one or more parameters, I get a validation error (value is invalid). For example, let's say I choose FullTime myself or choose FullTime and Retirement, then the following error will be displayed in the user interface:
The value "FullTime" is invalid.
The value "FullTime, Retirement" is invalid.
(respectively)
Even if I delete the int declaration for enum and get rid of the value that I started with "1", I still get this validation error. I tried to team up and add various bindings to the model (now I have a dead end that my original problem still exists, and now I have a different problem, but you still have bonus points :)).
I stretch my hair. If I could offer more generosity, I would do it. I need a final decision. I appreciate any help.
UPDATE This is what I have so far:
Record:
public virtual string IndividualIncomeTypeCheckBox{ get; set; }
Part:
//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); } }
Class of service:
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; ... }
And here is how it is called in the controller (this is stored in the database): (update controller code)
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); }
Update using additional code (serialization and view model):
"myData" is defined in the controller (using Serialization) as follows:
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; }
I use serialization because I set up a multi-stage wizard (as shown in the backButton "nextButton" controller action) on the interface. I do not use a driver (which can display only Admin or on the front -end, but only on .cshtml files directly in the ~ / Views folder (not in the list of structured folders as I use). There is no driver = there is no type view of the model code type = There is no mechanism for "creating" data in the DB. If I do not use any method like "create", the form will be submitted, but all the data will be "NULL".
When you say that data should be saved automatically, I'm sorry, but I don’t see how to do it. All the material that I read or the code that I look through has SOME method of updating the database with what is entered in the form. If I miss something, my apologies.
"MyViewModel" is pretty simple:
[Serializabel] public class MyViewModel { public SimplePartRecord SimplePartRecord { get; set; } }
And, just in case, here is the corresponding part of the migration (return 1 is a completely separate and unrelated table):
public int UpdateFrom1() { SchemaBuilder.CreateTable("SimplePartRecord", table => table .ContentPartRecord() ... .Column("IndividualIncomeTypeCheckBox", DbType.String) ... ); ContentDefinitionManager.AlterPartDefinition("SimplePart", part => part .Attachable(false)); return 2; }
The error I get is
Cannot implicitly convert type 'string' to 'System.Collections.Generic.IEnumerable' "
when I do the following in the Create method of my class of service:
simple.IndividualIncomeTypeCheckBox = record.IndividualIncomeTypeCheckBox;
Another thought: I tried to use the nn link pattern to handle this scenario. Besides the fact that this is a lot of additional code for what I thought should be simple and simple, due to the way I use serialization, I had many errors in the reference to the object and I could not figure out how to correctly encode my controller to handle it.