Posting separate lines from TextAreaFor into separate DB rows - c#

How can I get every line from TextAreaFor in Razor (or other form of HTML input) to be used by Create method (or how to modify that method) as separate value and inserted into separate row in DB.
Controller:
[HttpPost]
public ActionResult Create(Names name)
{
unitofwork.Names.Insert(name);
unitofwork.save();
return RedirectToAction("Index");
}
View
#Html.TextAreaFor(model => model.name)
Names Model
[Key]
public int NameID { get; set; }
[Required]
public string Opinion { get; set; }
[Required]
public int ID { get; set; }
public virtual NickName NickName { get; set; }

Try something like this:
[HttpPost]
public ActionResult Create(Names name)
{
var names = name.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
foreach(var n in names)
{
unitofwork.Names.Insert(n);
}
unitofwork.save();
return RedirectToAction("Index");
}

Related

MVCCheckBoxList catering for a 1 to Many relationship

I have a class for which has a 1 to many relationship with another class. for this I will use class Car and class Gears. I need to create a form, which registers a car and the user needs to specify a choice of gears.
public class Car
{
public int id { get; set; }
public string desc { get; set; }
public List<Gear> Gears { get; set; }
}
public class Gear
{
public int gid { get; set; }
public int gname { get; set; }
}
using asp.net MVC 5, I have a create form, which I have scaffolded to the Car model, and within the form, I wish to have a checkboxlist of gears,
I also have a ViewModel that I have provided for my checkboxlist which is as below:
public class GearsViewModel
{
public Gear _gear {get; set; }
public bool _isChecked {get; set;}
}
Controller looks like:
Gears fetched from db context will be
"GearR","Gear1","Gear2","Gear3","Gear4","Gear5","Gear6","Gear7"
public action Create()
{
ViewBag.Gears = new SelectList(db.Gears, "gid","gname");
List<GearViewModel> _gears= new List<GearViewModel>();
foreach(Gear G in ViewBag.Gears)
{
_gears.Add(new GearViewModel(G, false));
}
ViewBag.GearsCheckList = _gears.ToList();
return View();
}
Now, this is the part I'm getting stuck at, is how to display and capture details in the CreateView.
I need assistance on how to design the Create form and how I will capture the info.
Firstly, view models should not contain data models when editing. You view models should be (add validation and display attributes as appropriate)
public class CarVM
{
public int? ID { get; set; }
public string Description { get; set; }
public List<GearVM> Gears { get; set; }
}
public class GearVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
and the GET method will be
public ActionResult Create()
{
var gears = db.Gears;
CarVM model = new CarVM
{
Gears = gears.Select(x => new GearVM
{
ID = x.gid,
Name = x.gname
}).ToList()
};
return View(model);
}
and the view will then be
#model CarVM
....
#using (Html.BeginForm())
{
..... // elements for editing ID and Description properties of CarVM
#for (int i = ; i < Model.Gears.Count; i++)
{
<div>
#Html.HiddenFor(m => m.Gears[i].ID)
#Html.HiddenFor(m => m.Gears[i].Name) // include if your want to get this in the POST method as well
#Html.CheckboxFor(m => m.Gears[i].IsSelected)
#Html.LabelFor(m => m.Gears.IsSelected, Model.Gears[i].Name)
</div>
}
<input type="submit" .... />
}
Then in the POST method
public ActionResult Create(CarVM model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// To get the ID's of the selected gears
IEnumerable<int> selected = model.Gears.Where(x => x.IsSelected).Select(x => x.ID);
// Initialize your data models, save and redirect
}

EF not saving virtual properties when editing

I have a model Team which looks like this:
public class Team
{
[Key]
public int TeamId { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public virtual Group Group { get; set; }
}
I have a method to Edit it:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Team team)
{
using (var db = new DbConnection())
{
if (ModelState.IsValid)
{
db.Entry(team).State = EntityState.Modified;
db.Groups.Attach(team.Group);
db.SaveChanges();
}
return PartialView(team);
}
}
However it is not saving the change to the Group column. Meanwhile Create method does work although I see no difference between them:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Team team)
{
using (var db = new DbConnection())
{
if (ModelState.IsValid)
{
db.Groups.Attach(team.Group);
db.Teams.Add(team);
db.SaveChanges();
return RedirectToAction("Index");
}
return PartialView(team);
}
}
The values for the Group come the same in both methods. I bring the values to the form like this (again, same thing for both):
ViewBag.Groups = db.Groups.ToList().Select(g => new SelectListItem()
{
Text = g.Code,
Value = g.GroupId.ToString(),
Selected = false
}).ToList();
and use them like this:
#Html.DropDownListFor(model => model.Group.GroupId, (List<SelectListItem>)ViewBag.Groups)
Can someone please explain what the difference between the two methods is (in terms of one saving Group and other - not)?
P.S. Using both the latest MVC and EF.
Apparently it is a must (?) (at least I couldn't find anything better) to add a field matching the type of the Group in order to be able to easily save. No need to attach anything this way. Now my model looks like:
public class Team
{
[Key]
public int TeamId { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public int? GroupId { get; set; }
public virtual Group Group { get; set; }
}
and my Save and Create methods got this line:
db.Groups.Attach(team.Group);
removed.

Scaffolding ModelView creates underlying database tables

I'm trying to use ViewModels for the first time using AutoMapper. I have two models:
public class Item
{
public int ItemId { get; set; }
public bool Active { get; set; }
public string ItemCode { get; set; }
public string Name { get; set; }
public List<ItemOption> ItemOptions { get; set; }
//...
}
public class ItemOption
{
public int ItemOptionId { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
//...
}
Which I have turned into two ViewModels:
public class ItemDetailViewModel
{
public int ItemDetailViewModelId { get; set; }
public int ItemId { get; set; }
public bool Active { get; set; }
public string ItemCode { get; set; }
public string Name { get; set; }
public List<ItemDetailItemOptionViewModel> ItemOptions { get; set; }
}
public class ItemDetailItemOptionViewModel
{
public int ItemDetailItemOptionViewModelId { get; set; }
public int ItemOptionId { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
}
I then set the following in my application start-up:
Mapper.CreateMap<Item, ItemDetailViewModel>();
Mapper.CreateMap<ItemOption, ItemDetailItemOptionViewModel>();
Finally I scaffolded my ItemDetailViewModel:
I then built my project and added a new Item through /Item/Create
I had a look in the database expecting to see that I would have an entry in the Item table, but instead I have ItemDetailViewModel and ItemDetailItemOptionViewModel tables, which I wasn't expecting and the data is is ItemDetailViewModel.
I assume I have done something wrong with my scaffolding? How do I scaffold off the ViewModel without making it part of the main business models?
Further Details
If it isn't possible to scaffold the controller with a ViewModel, then how do I reference the ViewModel in the controller and save changes back to the database?
For example what would the following change to once I remove ItemDetailViewModel from the db context?
//
// POST: /Item/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ItemDetailViewModel itemdetailviewmodel)
{
if (ModelState.IsValid)
{
db.ItemDetailViewModels.Add(itemdetailviewmodel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(itemdetailviewmodel);
}
Further Details [2]
So am I correct that my Index/Details should work as so or is there a better way of doing it?
//
// GET: /Item/
public ActionResult Index()
{
var items = db.Items.ToList();
var itemdetailviewmodel = AutoMapper.Mapper.Map<ItemDetailViewModel>(items);
return View(itemdetailviewmodel);
}
//
// GET: /Item/Details/5
public ActionResult Details(int id = 0)
{
ItemDetailViewModel itemdetailviewmodel = AutoMapper.Mapper.Map<ItemDetailViewModel>(db.Items.Find(id));
if (itemdetailviewmodel == null)
{
return HttpNotFound();
}
return View(itemdetailviewmodel);
}
Scaffolding is not that intelligent. The standard controller scaffolding template is creating a DbContext with the controller model and presumes you are working with the DB models, not view models and it does not use Automapper. So you'll need to either not use scaffolding, or check what it has done before using it.
And nothing is wrong with the way you use scaffolding, it is just not supposed to do what you expect.
Update this is how you do this without scaffolding
// Without Automapper
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ItemDetailViewModel model)
{
if (ModelState.IsValid)
{
var item = new Item()
{
Active = model.Active,
ItemCode = model.ItemCode,
Name = model.Name,
ItemOptions = // code to convert from List<ItemDetailItemOptionViewModel> to List<ItemOption>
}
db.Items.Add(item);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
// with Automapper - not recommended by author of Automapper
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ItemDetailViewModel model)
{
if (ModelState.IsValid)
{
var item = Automapper.Mapper.Map<Item>(model);
db.Items.Add(item);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
You'll need to modify your DbContext to have IDbSet<Item> Items instead of IDbSet<ItemDetailViewModels> ItemDetailViewModels.
Automapper was created to map from Domain Models to View Models and not the other way. I have done that for a while, but this is troublesome and causes subtle bugs and other maintenance problems. Even Jimmy Bogard himself says you should not map from view models to domain models.

How to access selected item from dropdown in asp.net mvc3

i am using asp.net mvc3 and i populate a create view using following model
Model
public class CategoryModel
{
public int Id { get; set; }
public string Name { get; set; }
public string URL { get; set; }
public string Description { get; set; }
public string Logo { get; set; }
public bool IsActive { get; set; }
public bool isPopular { get; set; }
public IList<Category> Parentcategories { get; set; }
}
In my create View i populate like this
View
<div class="editor-field">
#Html.DropDownList("parentcategories", new SelectList(Model.Parentcategories.Select(c => c.Name), Model.Parentcategories.Select(c => c.Name)))
#Html.ValidationMessageFor(model => model.Parentcategories)
</div>
now how can i access the selected item in my controller method
Method
[HttpPost]
public ActionResult Create( CategoryModel model , HttpPostedFileBase file)
{
//
}
thanks,
Ahsan
Try this:
public ActionResult Create(string parentcategories, CategoryModel model , HttpPostedFileBase file)
parentcategories will contain selected option value.
As Smartboy already mentioned, you should use DropDownListFor:
1. append your model with public int ParentCategoryId { get; set; } field.
2. instead of using #Html.DropDownList use:
#Html.DropDownListFor(m => m.ParentCategoryId, new SelectList(...))
3. the server side can stay the same:
[HttpPost]
public ActionResult Create(CategoryModel model)
{
//
}
where model.ParentCategoryId will have selected item value.
Also note that you can first set selected item value for your view:
public ActionResult Index()
{
var model = CategoryModel();
...
model.ParentCategoryId = some_selected_value;
return View(model);
}
Details: You can access it directly from your model.
[HttpPost]
public ActionResult Create( CategoryModel model , HttpPostedFileBase file)
{
var selectedCategory = model.parentcategories; // something like that
}

foreign key not populating MVC3

Hi people I have the following code:
public ActionResult Create(GameTBL gametbl)
{
if (ModelState.IsValid)
{
//First you get the gamer, from GamerTBLs
var gamer = db.GamerTBLs.Where(k => k.UserName == User.Identity.Name).SingleOrDefault();
//Then you add the game to the games collection from gamers
gamer.GameTBLs.Add(gametbl);
db.SaveChanges();
return RedirectToAction("Index");
}
}
It is giving me the following error:
Error 1 'MvcApplication1.Controllers.GameController.Create(MvcApplication1.Models.GameTBL)': not all code paths return a value
What this code is trying to do is trying to populate the foreign key of gamer into the Game Table
Model for my controller Gamer:
public string UserName { get; set; }
public int GamerID { get; set; }
public string Fname { get; set; }
public string Lname { get; set; }
public string DOB { get; set; }
public string BIO { get; set; }
Model for my Game Controller:
public int GameID { get; set; }
public string GameName { get; set; }
public string ReleaseYear { get; set; }
public string Cost { get; set; }
public string Discription { get; set; }
public string DownloadableContent { get; set; }
public string Image { get; set; }
public string ConsoleName { get; set; }
public int GamerIDFK { get; set; }
public byte[] UserName { get; set; }
You just need to return a view when your ModelState isn't valid.
public ActionResult Create(GameTBL gametbl)
{
if (ModelState.IsValid)
{
//First you get the gamer, from GamerTBLs
var gamer = db.GamerTBLs.Where(k => k.UserName == User.Identity.Name).SingleOrDefault();
//Then you add the game to the games collection from gamers
gamer.GameTBLs.Add(gametbl);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(gametbl);
}
This will make the page show any errors in model creation (assuming you have validation).
try this...the return statement should be outside the if statement...the issue is you are not returning a view/action result when the modelstate is not valid...
public ActionResult Create(GameTBL gametbl)
{
if (ModelState.IsValid)
{
//First you get the gamer, from GamerTBLs
var gamer = db.GamerTBLs.Where(k => k.UserName == User.Identity.Name).SingleOrDefault();
//Then you add the game to the games collection from gamers
gamer.GameTBLs.Add(gametbl);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(gametbl);
}
Just so you know, the error isn't really ASP.Net MVC related - it would be an error in any method that returns a value.
The error message not all code paths return a value means just that - there is a path through the code that doesn't return a value, when the method signature says that it should.
In your case, your action method has the signature ActionResult Create(GameTBL gametbl) so all paths through the method have to return an ActionResult. In your code, the path that occurs when ModelState.IsValid is true does return an ActionResult - but nothing is returned in the path where ModelState.IsValid is false.
The other answers give you examples on how to correct your code by returning an ActionResult through the 'ModelState.IsValid is false' path.

Categories