I am using MVC 4.0 and entity-framework 5 to generate model.
I m trying to understand concept of customization, i followed same steps given in tutorials site like this and this
only difference is I am adding this customization class code in different sub folder because when directly try to add this in model folder it shows error employee class already created in this ( autogenrated by entity framwork)
Auto generated code By Entity Framework
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CustomizationConceptUmang.Models
{
using System;
using System.Collections.Generic;
public partial class employee
{
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
}
}
Code for customization
namespace CustomizationConceptUmang.Models.ViewModel
{
[MetadataType(typeof(employeeMetaData))]
public partial class employee
{
}
public class employeeMetaData
{
[Display(Name="Employee Name")]
public string name { get; set; }
}
}
View
<th>
#Html.DisplayNameFor(model => model.name)
</th>
Still it showing name instead of Employee Name
please suggest me how to resolve this Thanks in advance.
The partials are in different namespaces, so they're two separate classes and the metadata is not applied to the employee entity.
Match up the namespace to combine multiple partial classes into one.
Anyway don't use Entity Framework models as viewmodels. Create a separate class with annotations for a viewmodel, and map to and from your entity. You'll thank me later.
Related
I have an auto-generated Entity Framework model. It was generated using a database first approach. The mid_initial column has a database defined constraint that limits the column to a maximum length of 3 characters.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Agency.DataAccess.RegistrationModel
{
using System;
using System.Collections.Generic;
public partial class Registrant
{
public Registrant()
{
}
public int id { get; set; }
public string fname { get; set; }
public string mid_initial { get; set; }
public string lname { get; set; }
}
}
When I try and create a model with a mid_initial greater than 3 characters, a invalid state, ModelState.IsValid is returning true. Because of this db.SaveChanges is then called, which then raises DbEntityValidationException.
[HttpPost]
public ActionResult Create(Registrant registrant)
{
try
{
if (ModelState.IsValid)
{
Debug.WriteLine("Entity was valid.");
db.Registrants.Add(registrant);
db.SaveChanges();
return RedirectToAction("Index");
}
return View("Create", registrant);
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Debug.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
Debug.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
return View(registrant);
}
}
Why is the ModelState.IsValid method returning true? It would seem that my model is not aware of the maximum length constraint. How do I make it aware?
EF db-first can't infer constraints from database.
Use the MaxLenght data annotation attribute:
public partial class Registrant
{
public Registrant()
{
}
public int id { get; set; }
public string fname { get; set; }
[MaxLength(3, ErrorMessage = "")]
public string mid_initial { get; set; }
public string lname { get; set; }
}
Note: this class is a auto generated class and every time you update and save your model (.EDMX file), this code will be overwritten and you'll loose your attributes.
To avoid that, you should extend your classes with some partial classes with the same name and same namespace as your auto-generated classes. If you need examples to show you how, tell me to put it in answer.
MVC is EF-agnostic, and as such doesn't implicitly attempt to validate the model using EF validation to populate its ModelState.
You have four basic solutions I can think of right now:
Hook them up yourself, for example using MVC filters, DbContext.GetValidationErrors and ModelState.
Find and use third-party code that does this already.
Validate the code separately using facilities that MVC can use, for example using DataAnnotations. You may try to generate them automatically by modifying the EF T4 template. Note that this is still technically redundant (the code will be validated twice, once by MVC, once by EF).
Submit a patch for MVC so that it can support EF explicitly (as a soft dependency) and make it all just work (both projects are open source) -- or downvote me because they already did so and I never knew it.
In a MVC 3 solution, under VS 2012, it sounds strange that you receive such message after Running Code Analysis:
It is strange because the class which is mentioned in the "DON'T" analysis was generated by VS itself (not me).
To reproduce this you can:
add ADO.NET Entity Data Model to your solution,
add your database tables (already existent in SQL Server) to your diagram,
rebuild solution, add Controllers and cshtml views (those ones are generated automatically).
run the code analysis from ANALYZE menu.
So, the question is, what could we do: Refactor the auto-generated code or ignore this message?
Below a sample of auto generated class which violates the rule CA2214:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Backoffice.Entities
{
using System;
using System.Collections.Generic;
public partial class BR_SIMUL_Supermarket_Product
{
public BR_SIMUL_Supermarket_Product()
{
this.BR_SIMUL_Supermarket_Product_Price = new HashSet<BR_SIMUL_Supermarket_Product_Price>();
}
public int product_id { get; set; }
public int category_id { get; set; }
public string product_name { get; set; }
public string product_measure { get; set; }
public bool product_active { get; set; }
public virtual BR_SIMUL_Supermarket_Category BR_SIMUL_Supermarket_Category { get; set; }
more stuff here...
Here's how I solved it permanently: http://chuckbeasley.com/blog/?p=42200
This is by design to allow for lazy loading. When you access the classs through DbContext it won't fail at run-time despite the warning. You should suppress the warnings only in those files.
You should feel free to suppress these. Take a look at this discussion on the Entity Framework codeplex site for more details.
I am starting MVC4 with VS2012. I am also using EF5 with the "Database First" method of creating my classes.
However because the generated glasses can be regenerated I cannot put the Data Annotation details to assist with validation.
I have seen some code snippets that use MetaData and partial classes but I was wondering if anyone knows of a small compilable example that I can look at and pull apart to better understand how the vasious classes interlink.
Many many thanks for any help.
Dave
You can achieve what you need through extending models. Suppose that EF generated the following entity class for you:
namespace YourSolution
{
using System;
using System.Collections.Generic;
public partial class News
{
public int ID { get; set; }
public string Title { get; set; }
public int UserID { get; set; }
public virtual UserProfile User{ get; set; }
}
}
and you want do some work arounds to preserve your you data annotations and attributes. So, follow these steps:
First, add two classes some where (wherever you want, but it's better to be in Models) like the following:
namespace YourSolution
{
[MetadataType(typeof(NewsAttribs))]
public partial class News
{
// leave it empty.
}
public class NewsAttribs
{
// Your attribs will come here.
}
}
then add what properties and attributes you want to the second class - NewsAttribs here. :
public class NewsAttrib
{
[Display(Name = "News title")]
[Required(ErrorMessage = "Please enter the news title.")]
public string Title { get; set; }
// and other properties you want...
}
Notes:
1) The namespace of the generated entity class and your classes must be the same - here YourSolution.
2) your first class must be partial and its name must be the same as EF generated class.
Go through this and your attribs never been lost again ...
I have a model called Project, that has the following properties (simplified for brevity's sake).
[DataContract(IsReference = true)]
public class Project
{
[Key]
[DataMember]
public int id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime CreatedDate { get; set; }
}
The model is also a datacontract for a WCF service that uses Entity Framework 4 to query a datastore. The code for the model is generated from a template that automatically generates a CRUD service layer against the Entity Framework Model.
Now, my MVC2 application has a view containing a form to edit the fields. The controllers Edit action accepts the entire model as an argument upon POST.
[HttpPost]
public ActionResult Edit(Project project)
{
var context = new ServiceContext();
try
{
if (ModelState.IsValid)
{
project = context.UpdateProject(project);
return RedirectToAction("Index");
}
}
catch
{
ModelState.AddModelError("", "Could not save project");
}
return View(project);
}
Now, my problem is that when the form is posted to the controller, the Project model has all its fields correctly populated except for the 'id' property, which defaults to 0.
I've done some digging and pleaded with Uncle Google for answers, but the closest fix I could get was to add the following to the model's class,
[Bind(Include="id")]
which works fine, but ONLY populates the 'id' property, meaning that I would have to explicitly specify each property to be included in the model binding. Obviously, this can get nasty, especially since the model itself has many more properties than the one's I've shown above.
Is there any other way to get this working?
Gut feel is that the [Key] attribute has something to do with it, but I haven't been able to figure anything out.
The form has a hidden input for the 'id' property.
<%: Html.HiddenFor(model => model.id)%>
Try Adding additional hidden field for ID like <%: Html.HiddenFor(model => model.Id) %>
I think I have found the solution.
My model also has some complex properties which map to related tables in my entity framework model. Now, since I'm using the Self-Tracking Entities T4 templates to generate my service layer, it has some additional logic when it comes to mapping values to entities. In this case, one of the complex properties is a class called Status which looks like this:
public class Status
{
public int ProjectId { get; set; }
public int StatusId { get; set ; }
}
The ProjectId is a foreign key to the Project table in my datastore. I noticed that the ProjectId field was also set to 0 during model binding.
When I added the following to my view
<%: Html.HiddenFor(model => model.Status.ProjectId) %>
both fields had the correct value posted to the controller.
Problem solved :)
Thanks swapneel for your thoughts on the matter.
Using MVC3 and Entity Framework.
Am trying to get validation flowing from data model
Question: On an entity framework save, how can I automatically put in the [MetadataType tag below for my buddy class?
[EdmEntityTypeAttribute(NamespaceName="ModelValidationTestModel", Name="Person")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
[MetadataType(typeof(Person_Validation))] // I want EF to put this line in automatically
public partial class Person : EntityObject
...
[Bind(Exclude="PersonID")]
public class Person_Validation
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public int Age { get; set; }
[Required]
public string Email { get; set; }
}
Using example from: http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx
I think the best option is not to mess with the class generated by EF. Instead define your own partial class:
[MetadataType(typeof(Person_Validation))]
public partial class Person
{
//rest of class may be empty
}
You can do this in the same file as the Person_Validation class if you like.
It's not automatic, but it is safe (your changes won't get lost). This approach will work with any code generation framework (that uses partial classes), not just EF.
Data Annotations/attributes are baked at compile time and you cannot add them dynamically. I would recommend you to avoid passing/getting your EF models to/from the views. You should be using view models which are classes specifically tailored to the needs of a given view. It is those view models that will handle the would handle view specific validations such required, format, ...). You could then use AutoMapper to have your controller map between your view models and the EF models.