I used Entity Framework to generate my controller and view for my class.
This is what I have:
DemandeController.cs (controller):
public ActionResult Create()
{
Demande model = new Demande();
model.date = DateTime.Now;
model.status = "en cours";
Employe emp = (Employe)Session["currentUser"];
model.Employe = emp;
ViewBag.ServiceID = new SelectList(db.Services, "id", "nom");
ViewBag.EmployeID = new SelectList(db.Employes, "matricule", "nom");
return View(model);
}
Demande -> Create.cshtml (View)
<div class="editor-label">
#Html.LabelFor(model => model.EmployeID, "Employe")
</div>
<div class="editor-field">
#Html.DropDownList("EmployeID", String.Empty)
#Html.ValidationMessageFor(model => model.EmployeID)
</div>
Employe class:
public partial class Employe
{
public Employe()
{
this.ActivityLogs = new HashSet<ActivityLog>();
this.Demandes = new HashSet<Demande>();
}
public int matricule { get; set; }
public int DepartementID { get; set; }
public string nom { get; set; }
public string prenom { get; set; }
public string telephone { get; set; }
public string adresse { get; set; }
public string fonction { get; set; }
public string username { get; set; }
public string password { get; set; }
public string role { get; set; }
public Nullable<bool> isAdmin { get; set; }
public virtual ICollection<ActivityLog> ActivityLogs { get; set; }
public virtual ICollection<Demande> Demandes { get; set; }
public virtual Departement Departement { get; set; }
}
Demande class:
public partial class Demande
{
public int id { get; set; }
public int EmployeID { get; set; }
public int ServiceID { get; set; }
public Nullable<System.DateTime> date { get; set; }
public string status { get; set; }
public string details { get; set; }
public virtual Service Service { get; set; }
public virtual Employe Employe { get; set; }
}
By default, because I have many employees, the view generates a dropdownlist where I have to chose the employe name. That works without problems.
However, I am trying to change the dropdownlist into a textbox that would display the currently logged-in employe which is saved in a session object.
I tried a lot of things such as saving the Employe object in the model from the Controller like you can see in the Controller code above but it did not work as the View does not save the entire object to my understanding so when I submit, it overrides the Employe object and only leaves the name attribute. It worked for the date and status because they are basic objects but not for Employe.
I tried explaining to the best of capacity, I'm fairly new to ASP.NET MVC. If there is any further information you'd like me to provide, just let me know.
Related
I have 2 tables in my entity framework:
INATIVOS (Employees)
EMPRESAS (Companies)
When registering an employee I select a company in a #Html.DropDownListFor (List).
The registration is ok, the company is saved correctly. However, when trying to edit a registered employee shows the error "Unable to set field/property on entity" in the Companies list.
INATIVO.cs
public partial class INATIVOS
{
public decimal ID { get; set; }
public string COD_EMPRESA { get; set; }
public string CHAPA { get; set; }
public string NOME { get; set; }
public System.DateTime DATA_NASC { get; set; }
public string PLANO { get; set; }
public short LEI { get; set; }
public short APOSENTADO { get; set; }
public short ESTADO_VIDA { get; set; }
public short ISENTO { get; set; }
public Nullable<System.DateTime> INICIO_VIGENCIA { get; set; }
public Nullable<System.DateTime> FIM_VIGENCIA { get; set; }
public string CPF { get; set; }
public string EMAIL { get; set; }
public string ENDERECO { get; set; }
public string NUMERO { get; set; }
public string COMPLEMENTO { get; set; }
public string BAIRRO { get; set; }
public string CIDADE { get; set; }
public string ESTADO { get; set; }
public string CEP { get; set; }
public string TELEFONE { get; set; }
public string CELULAR { get; set; }
public string OBSERVACAO { get; set; }
public List<DEPENDENTES> DEPENDENTES { get; set; }
public List<EMPRESAS> EMPRESAS { get; set; }
public List<PLANOS_MEDICO> PLANOS_MEDICO { get; set; }
}
InativoController.cs
public ActionResult Index(int? id)
{
INATIVOS inaModel = new INATIVOS();
using (Entidades db = new Entidades())
{
if (id != null)
{
inaModel = db.INATIVOS.Where(x => x.ID == id).FirstOrDefault();
}
inaModel.EMPRESAS = db.EMPRESAS.ToList<EMPRESAS>();
inaModel.PLANOS_MEDICO = db.PLANOS_MEDICO.ToList<PLANOS_MEDICO>();
}
return View(inaModel);
}
If these are navigation properties:
public List<DEPENDENTES> DEPENDENTES { get; set; }
public List<EMPRESAS> EMPRESAS { get; set; }
public List<PLANOS_MEDICO> PLANOS_MEDICO { get; set; }
Then (1) they need to be virtual and (2) they need to be something like IList or ICollection:
public virtual ICollection<DEPENDENTES> DEPENDENTES { get; set; }
public virtual ICollection<EMPRESAS> EMPRESAS { get; set; }
public virtual ICollection<PLANOS_MEDICO> PLANOS_MEDICO { get; set; }
Though, as an aside, what you're doing here is very strange:
inaModel.EMPRESAS = db.EMPRESAS.ToList<EMPRESAS>();
inaModel.PLANOS_MEDICO = db.PLANOS_MEDICO.ToList<PLANOS_MEDICO>();
Essentially what you have in the database is, for a given Employee (INATIVOS) there are relationships to specific Companies (EMPRESAS) and specific Medical Plans (PLANOS_MEDICO). But you're ignoring whatever is in that data and replacing it with all companies and all medical plans in the entire database.
So every time you use this controller action to fetch an existing employee record, it's going to look like that employee has every company and every medical plan. Even though that's not what's in the database. I strongly suspect that's not what you want.
UPDATE: Based on comments on this answer, it sounds like those aren't navigation properties. They're not even properties of the model at all. They're just lists of data needed for the view to populate (presumably) <select> elements.
If they're not part of the data model then remove them from the model. Instead, consider using a view model. For example:
public class InativosViewModel
{
public INATIVOS Inativos { get; set; }
public List<EMPRESAS> EMPRESAS { get; set; }
public List<PLANOS_MEDICO> PLANOS_MEDICO { get; set; }
}
Then in the controller return an instance of the view model, which is a composite object of the model and the data needed for the view:
public ActionResult Index(int? id)
{
InativosViewModel result = new InativosViewModel();
using (Entidades db = new Entidades())
{
if (id != null)
{
result.Inativos = db.INATIVOS.Where(x => x.ID == id).FirstOrDefault();
}
result.EMPRESAS = db.EMPRESAS.ToList<EMPRESAS>();
result.PLANOS_MEDICO = db.PLANOS_MEDICO.ToList<PLANOS_MEDICO>();
}
return View(result);
}
And of course change the model binding in the view itself to now expect and use an instance of InativosViewModel. The resulting POST action can still accept an instance of INATIVOS if it needs to, or it can accept an instance of InativosViewModel just as well. That all depends on what the form structure is and what's being posted to that action.
Alternatively, if you want to keep using the INATIVOS model then still remove those lists from it but use something like ViewBag to send them to the view. Something like this:
public ActionResult Index(int? id)
{
INATIVOS inaModel = new INATIVOS();
using (Entidades db = new Entidades())
{
if (id != null)
{
inaModel = db.INATIVOS.Where(x => x.ID == id).FirstOrDefault();
}
ViewBag.Empresas = db.EMPRESAS.ToList<EMPRESAS>();
ViewBag.PlanosMedico = db.PLANOS_MEDICO.ToList<PLANOS_MEDICO>();
}
return View(inaModel);
}
Then in your view you would populate the <select> elements from there:
#Html.DropDownListFor(
model => Model.COD_EMPRESA,
new SelectList(ViewBag.Empresas, "CODIGO", "DESCRICAO"),
htmlAttributes: new { #class = "form-control"
})
What is the best practice when I have 2 or more models, and I would like to use the properties of all those models in a form?
namespace TestApplication.Models
{
public class Parent
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
public string City { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
}
}
namespace TestApplication.Models
{
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public int Grade { get; set; }
public char Class { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
}
}
=== I need the resulting ViewModel to be passed into a FormController action to process the form.
=== the form (cshtml file) itself would contain input fields for all the properties of both classes. I would also like to have more than 2 classes in the form.
should I use AutoMapper and map both/multiple models into one ViewModel?
If yes, what would be the best approach to this?
should I rather create a common FormClass that would have both Student and Parent classes as properties?
is there another/better way?
For This I would suggest following solution. I partially agree with your second point.
Models should look like this.
public class Parent
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
public string City { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
}
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public int Grade { get; set; }
public char Class { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
}
public class FormClass // This is what you suggested but it use other two model
{
public Student Student { get; set; }
public Parent Parent { get; set; }
}
View should use FormClass
#model HelloMvc.FormClass
<form method="post" action="/">
<div class="row">
<div class="col-md-4">
#Html.EditorFor(cc=>cc.Parent)
</div>
<div class="col-md-4">
#Html.EditorFor(cc=>cc.Student)
</div>
<div class="col-md-4">
<input type="submit" />
</div>
</div>
</form>
Note :
Controller Should look like this.
public class HomeController : Controller
{
[HttpGet("/")]
public IActionResult Index()
{
return View();
}
[HttpPost("/")]
public IActionResult Index(FormClass model)
{
return View(model);
}
}
The best approach is to use different names for similar properties. For example for Email in Parent use ParentEmail and for Student use StudentEmail.
Since you own the presentation layer, I would go with #2 for simplicity and fast to produce/deploy and I don't have to worry about fields that I am sending to the client. If this app is an API, I will go with #1 and use Automapper using Profile to map the view model to your domain classes.
Please help solve my problem. I want get message if textbox TagsSites is empty.
My models:
Site:
public int Id { get; set; }
[Required]
public string UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string TypeMenuId { get; set; }
public virtual IList<Page> Pages { get; set; }
[Required]
public virtual IList<TagSite> TagsSites { get; set; }
public virtual TypeMenu TypeMenu { get; set; }
public virtual ApplicationUser User { get; set; }
Tag:
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<TagSite> TagsSites { get; set; }
TagSite:
public int Id { get; set; }
public int SiteId { get; set; }
public int TagId { get; set; }
public virtual Site Site { get; set; }
public virtual Tag Tag { get; set; }
I now get this message for all empty inputs.
How to get message "The TagsSites field is required." ?
Thanks.
What you may want here is the MinLengthAttribute. Implementation looks something like this.
[Required]
[MinLength (1)]
public virtual IList <TagSite> TagSites { get; set; }
You should create a view model for your view with a property for a comma separated tag names and mark it with the Required attribute.
public class CreateSiteVm
{
[Required]
public string Name { set;get;}
[Required]
public string Description { set;get;}
[Required]
public string Tags { set;get;}
[Required]
public int TypeMenuId { set;get;}
public List<SelectListItem> TypeMenus { set;get;}
}
and in your GET action
public ActionResult Create()
{
var vm = new CreateSiteVm();
vm.TypeMenus = dbContext.TypeMenus.Select(x=> new SelectListItem {
Value=x.Id.ToString(),
Text=x.Name}).ToList();
return View(vm);
}
and in your view,
#model CreateSiteVm
#using(Html.BeginForm())
{
<p>#Html.ValidationSummary(false)</p>
<label>Name</label>
#Html.TextBoxFor(f=>f.Name)
<label>Descsription</label>
#Html.TextBoxFor(f=>f.Descsription)
<label>Tags</label>
#Html.TextBoxFor(f=>f.Tags)
<input type="submit" />
}
and in your HttpPost action method, create an object of your entity and set the values from view model object which is your method parameter. You can use Split method to split the comma separated string.
[HttpPost]
public ActionResult Create(CreateSiteVm model)
{
if(ModelState.IsValid)
{
var e=new Site { Name = model.Name, Description = model.Description};
e.TypeMenuId = model.TypeMenuId;
var arr = model.Tags.Split(',');
foreach (var s in arr)
{
e.Tags.Add(new Tag { Name = s});
}
dbContext.Sites.Add(e);
dbContext.SaveChanges();
return RedirectToAction("Index");
}
//to do : Load the dropdown again same as GET
return View(model);
}
I would like to populate certain parts of a view with certain fields from a database. I'm not sure exactly how to make this work. This is my current situation...
Here is my controller action:
public ActionResult Course_page(string id)
{
string abbrev = id;
var cpage = from c in db.Course_page
select c;
if (!String.IsNullOrEmpty(abbrev))
{
cpage = cpage.Where(x => x.abbrev.Contains(abbrev));
}
return View(cpage);
}
My Model:
[Table("course_page")]
public class Course_page
{
[Key]
public int CourseID { get; set; }
public string Meta { get; set; }
public string Title { get; set; }
public string Country { get; set; }
public string main_image { get; set; }
public string list_1 { get; set; }
public string list_2 { get; set; }
public string list_3 { get; set; }
public string list_4 { get; set; }
public string list_5 { get; set; }
public string list_6 { get; set; }
public string list_7 { get; set; }
public string list_8 { get; set; }
public string list_9 { get; set; }
public string list_10 { get; set; }
public string testim_1 { get; set; }
public string testim_2 { get; set; }
public string testim_3 { get; set; }
public string course_site { get; set; }
public string popup_script { get; set; }
public string abbrev { get; set; }
}
The view (shortened):
#model IEnumerable<oltinternational_mvc.Models.Course_page>
<div id="main_container">
<article class="content">
<h1>{#Html.DisplayNameFor(modelItem => cpage.Title)}</h1>
</article>
</div>
I get that I have to reference the cpage variable somewhere on the view but I'm not sure exactly in what manner. The idea is that the course page will load with the correct details as per the ID provided by the URL.
Please could someone advise me how I am to include the cpage variable in the view file or if I am doing this the correct way at all?
You are doing it correct way just change this helper :
{#Html.DisplayNameFor(modelItem => cpage.Title)} to
#Html.DisplayNameFor(modelItem => modelItem .Title)
And print the data in foreach loop because you can have more than one result.
I'm getting data set to POST action method's model object like following
Once I expand above object , it has following properties
Once I expand above ListProductFields IList , it has following properties
Once I expand above ListProductFields IList's object values , [0]th value it has following properties and its values
this is the relevant model class files
public class AddNewProduct
{
public string Product_ID { get; set; }
public string ProductTypeID { get; set; }
public string ProductCategoryID { get; set; }
public string Subsidary_ID { get; set; }
public string Field_ID { get; set; }
public string ProductFieldNameEn { get; set; }
public string ProductFieldNameAr { get; set; }
public string ApprovalStatus { get; set; }
public string Status { get; set; }
public IList<AB_ProductTypeCategoryField> ListProductFields { get; set; }
}
public partial class AB_ProductTypeCategoryField
{
public string ProductFieldID { get; set; }
public string ProductFieldNameEn { get; set; }
public string ProductFieldNameAr { get; set; }
public string ProdcutFieldDiscriptionEn { get; set; }
public string ProductFieldDiscriptionAr { get; set; }
public string Status { get; set; }
public bool IsChecked { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public string UpdatedBy { get; set; }
public Nullable<System.DateTime> UpdatedDate { get; set; }
public string Field_Value_EN { get; set; }
public string Field_Value_AR { get; set; }
}
public partial class AB_Product_vs_Field
{
public string Product_ID { get; set; }
public string Field_ID { get; set; }
public string Field_Value_EN { get; set; }
}
I have database table call AB_Product_vs_Field and I want to insert ,
ProductFieldID ,Field_ID , Field_Value_EN from those values from last image
since these are 19 objects have to insert to the AB_Product_vs_Field database table I may have to use a loop .
so I created following linq query to insert data to that table
[HttpPost]
[ValidateInput(false)]
public ActionResult Add_Product(AddNewProduct product)
{
AB_Product_vs_Field insertproductvalue = new AB_Product_vs_Field();
if (ModelState.IsValid)
{
for (int i = 0; i < product.ListProductFields.Count; i++)
{
insertproductvalue.Product_ID = product.Product_ID;
insertproductvalue.Field_ID = product.ListProductFields[i].ProductFieldID;
insertproductvalue.Field_Value_EN = product.ListProductFields[i].Field_Value_EN;
};
db.AB_Product_vs_Field.Add(insertproductvalue);
db.SaveChanges();
}
}
but I'm getting following error
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
I put debug point in front of this line db.AB_Product_vs_Field.Add(insertproductvalue); of my code.once this line calling its directing to following section in App_Browsers.9u0xu-_o.0.cs file
public class ApplicationBrowserCapabilitiesFactory : System.Web.Configuration.BrowserCapabilitiesFactory {
public override void ConfigureCustomCapabilities(System.Collections.Specialized.NameValueCollection headers, System.Web.HttpBrowserCapabilities browserCaps) {
}
this is the error page I'm getting once this line called
these are the images of error
Image 1:
Image 2:
I added the following line in the for loop, then it can keep a record of every tuple
#Html.HiddenFor(m => m.ListProductFields[i].ProductFieldID)
then my view page appeared like this
<div class="col-md-10">
#Html.HiddenFor(m => m.ListProductFields[i].ProductFieldID)
#Html.TextAreaFor(m => m.ListProductFields[i].Field_Value_EN,
new { #class = "form-control summernote", #row = 5 })
</div>