I am trying to update supplier in database when users on webform insert data into textboxes.
First users in textbox for supplierID insert value, and on screen shows particular supplier from database. Then user can change supplier and when he is done he have to click on submit button.
I use EntityState.Modifier, but supplier doesn't change in database, and also I have no errors in the view. I think that's not working because my Supplier have foreign key from Adress table.
Does somebody know how to update using Entity state modified if a have a foreign key to another table?
I appreciate any help!
public partial class Supplier
{
public int SupplierID{ get; set; }
public string Name{ get; set; }
public string Phone{ get; set; }
public string Email { get; set; }
public Nullable<int> TownID{ get; set; }
public Nullable<int> StreetID{ get; set; }
public Nullable<int> AdressNumber{ get; set; }
public virtual Adress Adress { get; set; }
}
public partial class Town
{
public int TownID{ get; set; }
public string Name{ get; set; }
}
public partial class Street
{
public int TownID{ get; set; }
public int StreetID{ get; set; }
public string Name{ get; set; }
}
public partial class Adress
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Adress()
{
this.Supplier= new HashSet<Supplier>();
}
public int TownID{ get; set; }
public int StreetID{ get; set; }
public int AdressNumber{ get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Supplier> Suppliercs{ get; set; }
}
This is my View:
#model FpisNada.Models.Supplier
#{
ViewBag.Title = "Index";
Layout = null;
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.TextBoxFor(model => model.SupplierID, new { #placeholder = "pib dobavljaca", style = " float:left" })
<div class="col-md-9">
#if (ViewBag.ListTown!= null)
{
#Html.DropDownListFor(m => m.TownID, ViewBag.ListTown as SelectList, "--select town--", new { #class = "form-control", style = " float:left" })
}
#Html.DropDownListFor(m => m.StreetID, new SelectList(""), "--select street--", new { #class = "form-control", style = " float:left" })
<div class="container">
#Html.TextBoxFor(model => model.AdressNumber, new { #class = "form-control"})
#Html.TextBoxFor(model => model.Email, new { #class = "form-control" })
#Html.TextBoxFor(model => model.Name, new { #class = "form-control" })
#Html.TextBoxFor(model => model.Phone, new { #class = "form-control"})
</div>
</div>
<input type="submit" value="Edit" />
}
My controller method:
[HttpGet]
public ActionResult Edit(int id)
{
Supplier supplier= db.Supplier.Find(id);
return View(supplier);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit( Supplier supplier)
{
try
{
if (ModelState.IsValid)
{
db.Entry(supplier).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("ChangeSupplier");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
return View(supplier);
}
Related
I am using EF and my relationship between tables is many-to-many. I want to display and edit the ICollection property to not only display my ingredients from a recipe, but to also edit, add, or delete them.
I tried to use EditorFor, but the changes of the ingredient were never changed and submitted to the database. I want to use DropDownList because it can show the ingredients that my recipe has in a list format so I can choose between them.
This is my Recipe and Ingredients Model with the relational table RecipesIngredients:
namespace Licenta.Models
{
public class Recipe
{
[Key]
public int IDRecipe { get; set; }
public string Name { get; set; }
public string Desc { get; set; }
public string Steps { get; set; }
public float Kcal { get; set; }
public float Pro { get; set; }
public float Carbo { get; set; }
public float Fat { get; set; }
public virtual ICollection<RecipesIngredients> RecipesIngredients { get; set; }
}
}
namespace Licenta.Models
{
public class RecipesIngredients
{
[Key]
[Column(Order = 1)]
public int IDRecipe { get; set; }
[Key]
[Column(Order = 2)]
public int IDIngredient { get; set; }
public virtual Recipe Recipe { get; set; }
public virtual Ingredient Ingredient { get; set; }
}
}
namespace Licenta.Models
{
public class Ingredient
{
[Key]
public int IDIngredient { get; set; }
public string Nume { get; set; }
public float Kcal { get; set; }
public float Pro { get; set; }
public float Carbo { get; set; }
public float Fat { get; set; }
public virtual ICollection<RecipesIngredients> RecipesIngredients { get; set; }
}
}
This is my Controller:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Recipe recipe = db.Recipes.Find(id);
if (recipe == null)
{
return HttpNotFound();
}
return View(recipe);
}
// POST: Recipes/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "IDRecipe,Name,Kcal,Pro,Carbo,Fat,Desc,Steps,Ingredients,RecipesIngredients")] Recipe recipe)
{
if (ModelState.IsValid)
{
db.Entry(recipe).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(recipe);
}
And the View of the Edit page:
#model Licenta.Models.Recipe
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Rețetă</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.IDRecipe)
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#foreach (var item in Model.RecipesIngredients)
{
<td>
#Html.DropDownListFor(model => item.Ingredient.Nume, #* this is where i want to edit the ingredients*#)
</td>
}
<div class="col-md-10">
#Html.ValidationMessageFor(model => model.RecipesIngredients, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
That is the View that I want to use to edit my ingredients. Is there any way to do that?
I am using an existing sql database in my MVC application. For one of the tables, the create/update functions do not work. I am assuming it is because my application fails to retrieve the auto generated ID's defined in SQL and hence inserts a null value into a non nullable field resulting in the application breaking. So, my question is how do i retrieved the auto generated fields defined in my sql database to show in my MVC5 application. Many thanks to anybody who can assist.
Below is my database table for Customers:
The Model:
public partial class Customer
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Customer()
{
this.Cards = new HashSet<Card>();
this.Stores = new HashSet<Store>();
}
public int CustomerID { get; set; }
public int DiscountLevelID { get; set; }
public int LoyaltyLevelID { get; set; }
public string CustomerCompanyName { get; set; }
public string CustomerName { get; set; }
public string CustomerSurname { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string CustomerGUID { get; set; }
public int CustomerStatus { get; set; }
public string CustomerAddress { get; set; }
public string CustomerTel { get; set; }
public string CustomerCel { get; set; }
public Nullable<int> CustomerNumber { get; set; }
public string CustomerContact { get; set; }
public string CustomerLogo { get; set; }
public string CustomerLogoPath { get; set; }
public int LastStoreCustomerSyncID { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Card> Cards { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Store> Stores { get; set; }
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CustomerID,DiscountLevelID,LoyaltyLevelID,CustomerCompanyName,CustomerName,CustomerSurname,CustomerGUID,CustomerStatus,CustomerAddress,CustomerTel,CustomerCel,CustomerNumber,CustomerContact,CustomerLogo,CustomerLogoPath,LastStoreCustomerSyncID")] Customer customer)
{
if (ModelState.IsValid)
{
db.Customers.Add(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(customer);
}
// GET: Companies/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Customer customer = db.Customers.Find(id);
if (customer == null)
{
return HttpNotFound();
}
return View(customer);
}
// POST: Companies/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "CustomerID,DiscountLevelID,LoyaltyLevelID,CustomerCompanyName,CustomerName,CustomerSurname,CustomerGUID,CustomerStatus,CustomerAddress,CustomerTel,CustomerCel,CustomerNumber,CustomerContact,CustomerLogo,CustomerLogoPath,LastStoreCustomerSyncID")] Customer customer)
{
if (ModelState.IsValid)
{
db.Entry(customer).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(customer);
}
The View
<div class="form-group">
#Html.LabelFor(model => model.CustomerGUID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CustomerGUID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CustomerGUID, "", new { #class = "text-danger" })
</div>
</div>
So, my question is how do i retrieved the auto generated fields
defined in my sql database to show in my MVC5 application.
Follow steps
Right click on the designer surface of the EDMX designer and click Update Model From Database...
All entities are refreshed by default, new entities are only added if you select them.
EDIT: If it is not refreshing well.
Select all the tables and view-s in the EDMX designer.
Delete them.
Then, update model from database
Right click On Model1.tt and select 'Run Custom Tool' save and Build Now see classes are generated.
Right click On Model1.Context.tt and select 'Run Custom Tool' save and Build Now see property IN Context class is generated like
P.S
Read this link also, it is very useful: http://blog.jongallant.com/2012/08/entity-framework-manual-update/
You should pass CustomerID to Controller as parameter. Don't give permission to CustomerID for null values and make it AUTO_INCREMENT
<div class="form-group">
#Html.TextBoxFor(model => model.CustomerID, new {style = 'display:none'})
#Html.LabelFor(model => model.CustomerGUID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CustomerGUID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CustomerGUID, "", new { #class = "text-danger" })
</div>
</div>
I have a page that show details of a post and Identified users can add commented on that post.
My problems:
PostID and UserID is FK in Comment model and don't pass from view to controller
CommnetMessage is Null!!
what is wrong?
Comment Model :
public class Comment : System.Object
{
public Comment()
{
this.CommnetDate = General.tzIran();
}
[Key]
public int CommentID { get; set; }
[Required]
public string CommnetMessage { get; set; }
[Required]
public DateTime CommnetDate { get; set; }
public string UserId { get; set; }
[Key, ForeignKey("UserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public int PostID { get; set; }
[Key, ForeignKey("PostID")]
public virtual Post posts { get; set; }
}
Post Model:
public class Post : System.Object
{
public Post()
{
this.PostDate = General.tzIran();
this.PostViews = 0;
}
[Key]
public int PostID { get; set; }
public string PostName { get; set; }
public string PostSummery { get; set; }
public string PostDesc { get; set; }
public string PostPic { get; set; }
public DateTime PostDate { get; set; }
public int PostViews { get; set; }
public string postMetaKeys { get; set; }
public string PostMetaDesc { get; set; }
public string UserId { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public int CategoryID { get; set; }
[ForeignKey("CategoryID")]
public virtual Category Category { get; set; }
public virtual ICollection<Comment> commnets {get; set;}
}
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
/*Realations*/
public virtual ICollection<Comment> Comments { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
View Model:
public class PostViewModel
{
public ApplicationUser Users { get; set; }
public Post posts { get; set; }
public Category Categories { get; set; }
public IEnumerable<Comment> ListCommnets { get; set; }
public Comment Commnets { get; set; }
}
Controller:
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var post = db.Posts.Find(id);
post.PostViews += 1;
db.SaveChanges();
if (post == null)
{
return HttpNotFound();
}
return View(new PostViewModel() { posts = post });
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Details([Bind(Include = "CommentID,CommnetMessage,CommnetDate,UserId,PostID")] Comment comment , int? id)
{
int pid = comment.PostID;
if (ModelState.IsValid)
{
db.CommentS.Add(comment);
db.SaveChanges();
TempData["notice"] = "پیغام شما با موفقیت ثبت شد.";
return RedirectToAction("success");
}
ViewBag.UserId = new SelectList(db.Users, "Id", "FirstName", comment.UserId);
ViewBag.PostID = id;
return View( new PostViewModel() { posts = db.Posts.Find(id)});
}
public ActionResult success()
{
ViewBag.Message = "از طریق فرم زیر می توانید برایمان پیغام بگذارید.";
return View("Details", new PostViewModel() { ListCommnets = db.CommentS });
}
Comment Partial View:
#using Microsoft.AspNet.Identity
#using FinalKaminet.Models
#using Microsoft.AspNet.Identity.EntityFramework
#model FinalKaminet.ViewModel.PostViewModel
#if (TempData["notice"] != null)
{
<p>#TempData["notice"]</p>
}
#if (Request.IsAuthenticated)
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = manager.FindById(User.Identity.GetUserId());
using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.posts.PostID)
#Html.HiddenFor(model => model.Users.Id)
<div class="form-group">
#Html.LabelFor(model => model.Users.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#{
var name = user.FirstName + " " + user.LastName;
}
<input type="text" id="Id" value="#name" disabled="disabled" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Commnets.CommnetMessage, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Commnets.CommnetMessage, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Commnets.CommnetMessage, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Send" class="btn btn-default" />
</div>
</div>
</div>
}
}
else
{
<p>#Html.ActionLink("Log in", "Login", "Account", new { returnUrl = Request.Url }, null)</p>
}
As #StephenMuecke stated, model of your view is PostViewModel and all editors, hidden fields are created based on your view model. For example, when you generate hidden field using #Html.HiddenFor(model => model.posts.PostID) and try to post your data MVC model binder tries to bind the value of this field to the model specified at your Action method. In your case it is Comment so , MVC model binder will try bind value of generated hidden field to Comment.posts.PostID which does not exist. To make everything work perfectly you have to use same view model as a argument of your action method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Details(PostViewModel viewModel)
{
......
}
Also, again as #StephenMuecke sated, your view model should have only those properties which you need. For example, your PostViewModel should look like something as following:
public class PostViewModel
{
// Actually, you do not need UserId property
// as it should be retrieved inside controller
// from current user data
public string UserId { get; set; }
public string UserName { get; set; }
public int PostID { get; set; }
public string CommentMessage { get; set; }
}
Back to your action method, you have to map view model to your model:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Details(PostViewModel viewModel)
{
Comment comment = new Comment
{
CommnetMessage = viewModel.CommentMessage,
// and other properties
}
// Save your model and etc.
}
I have the following entities:
public class Entidad
{
[Key]
public int Id { get; set; }
public string Nombre { get; set; }
public virtual ICollection<Propiedad> Propiedades { get; set; }
}
public class Propiedad
{
[Key]
public int Id { get; set; }
public virtual Entidad Entidad { get; set; }
public string Codigo { get; set; }
public string Nombre { get; set; }
public string TipoDeDatos { get; set; }
}
And I have this controller action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="Id,Codigo,Nombre,TipoDeDatos")] Propiedad propiedad)
{
if (ModelState.IsValid)
{
db.Propiedades.Add(propiedad);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(propiedad);
}
and on my view:
<div class="form-group">
#Html.LabelFor(model => model.Entidad, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.Entidad.Id, (SelectList)(ViewBag.EntidadList), "Seleccionar", new { #class = "form-control" })
</div>
</div>
However when I debug the controller the Entidad property on the Propiedad entity is NULL
http://screencast.com/t/CSgLzSCw
In the declaration on DataAnnotation Bind at the Create method, you are not including Entidad property, never will be binded, just remove the Bind DataAnnotation or include it.
I try to add new entity in database in controller action.
This is my model class
public class Product
{
public int ProductID { get; set; }
[Required(ErrorMessage = "Please enter product name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter product model")]
public string Model { get; set; }
[Required(ErrorMessage = "Please enter product serial")]
public string Serial { get; set; }
[Required(ErrorMessage = "Please choose dealer")]
public int DealerID { get; set; }
[Required]
public Guid ClientID { get; set; }
[Required(ErrorMessage = "Please choose employee")]
public Guid EmployeeID { get; set; }
public virtual Dealer Dealer { get; set; }
public virtual Client Client { get; set; }
public virtual Employee Employee { get; set; }
[DisplayName("Commercial use")]
public bool UseType { get; set; }
}
This is actions for creating new product in database
public ViewResult Create()
{
PopulateDropDownLists();
var model = new Product();
return View(model);
}
[HttpPost]
public ActionResult Create(Product model)
{
try
{
if (ModelState.IsValid)
{
_repo.GetRepository<Product>().Add(model);
_repo.Save();
TempData["message"] = "Product was successfully created";
return RedirectToAction("List");
}
}
catch (DataException)
{
TempData["error"] =
"Unable to save changes. Try again, and if the problem persists, see your system administrator.";
return View("Error");
}
PopulateDropDownLists();
return View("Create");
}
CreateView has appropriate model type (Product type in this case). Code below
#using System.Web.Mvc.Html
#model STIHL.WebUI.Models.Product
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.Name)
#Html.EditorFor(m => m.Model)
#Html.EditorFor(m => m.Serial)
<div class="form-group">
#Html.LabelFor(m => m.DealerID, "Dealer")
#Html.DropDownListFor(m => m.DealerID, new SelectList((IEnumerable)TempData["Dealers"],"DealerID", "DealerNumber"), string.Empty, new {#class = "form-control"})
#Html.ValidationMessageFor(m => m.DealerID, null, new {#class = "help-block"})
</div>
<div class="form-group">
#Html.LabelFor(m => m.EmployeeID, "Employee",new {#class = "control-label"})
#Html.DropDownListFor(m => m.EmployeeID, new SelectList((IEnumerable)TempData["Employees"],"EmployeeID", "FullName"),string.Empty, new {#class="form-control"})
#Html.ValidationMessageFor(m => m.EmployeeID, null, new {#class = "help-block"})
</div>
<div class ="ok-cancel-group">
<input class="btn btn-primary" type="submit" value="Create" />
#Html.ActionLink("Cancel", "List","Product",new {#class = "btn btn-primary"})
</div>
}
i always get null reference instead model in [HttpPost] action, but if i use ViewModel instead Model everything is ok (ViewModel code below)
public class ProductViewModel
{
public Product Product { get; set; }
}
I think it cause model class has virtual properties, but anyway i don't understand why it's ok when i use ViewModel.
Can anyone answer me?
Thx in advance.
The virtual properties won't change the outcome. The issue is that the view is written to bind to the view model, therefore accepting the model isn't going to work. If you want to use the model; then bind the view to the model.