Adding new virtual property to model MVC3 EF4 - asp.net-mvc-3

I recently just learned about putting your data annotations in a new partial class so that they persist on edmx updates from the database.
Database-first approach and modifying the database schema
Update Model From Database (Database First)
In one of my models I have two attributes: firstName and lastName.
I had created a virtual property for full name seen below.
public virtual string fullName { get {return firstName + " " + lastName; } }
The fullName property works when it's in the edmx generated .tt model class, but when I put it in my "buddy" partial class that hold my annotations, it doesn't work (ie isn't recognized by the rest of the app as an attribute of my class).
How do I get a aggregate virtual property like the fullName property above that won't be overwritten by a database update to the edmx?

I figured it out. The accompanying partial class for data annotations has a classMetaData class that you use to set the Meta Data for your partial class (ie your annotations go here). The aggregate attribute has to go in the partial class though (not the Meta Data class).
So the second partial class code should look something like this:
namespace MyProject.Models
{
[MetadataType(typeof(PersonMetaData))]
public partial class Person
{
//this is where you put new aggregate properties
public virtual string fullName { get { return firstName + " " + lastName; } }
}
public class PersonMetaData
{
//this is where you put data annotations
[Required]
public string firstName { get; set; }
[Required]
public string lastName { get; set; }
}
}

Related

RequiredAttribute doesn't appear on client-side validation, on derived class

My viewmodel inherits from a class that inherits from an abstract class that has a property with a [Required] attribute, but the rule doesn't appear in the DOM and unobtrusive validation doesn't catch the error.
The display attribute goes through fine, but the validation DOM attributes are not added to the textarea
my view has this:
#model FormPersonView
....
#Html.TextAreaFor(m => m.Description)
#Html.ValidationMessageFor(m => m.Description)
my code has this:
public class FormPersonView : Person
{
//View related stuff
.....
.....
}
public class Person : BasePerson
{
//Person related stuff - validation for these work!
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
public abstract class BasePerson
{
//Base person stuff - validation for this doesn't work!
public string Id { get; set; }
[Required]
[Display("Short description of the person")]
public string Description { get; set; }
}
Why does it work with one level of inheritance but not two? It does work on the server side.
Had exactly this problem. While defining the view, the model comes as a type you defined #model FormPersonView. Data annotations will only work on that specific type, even if you have derived properties from children, their data annotations won't be engaged.
The solution that I came up with in my project was to define editor templates for types I needed data annotations to work properly and then calling #EditorFor on those models. Then and only then were data annotations operating as expected.
Hope this help you.

Giving error while creating partial class

I am developing MVC application in which , I am trying to create the partial class of class generated by MVC application lets say Location class.
Now I want to create the partial class of Location class in new class file.
The below class code is auto genrated by MVC of Location code.
namespace CRM
{
public partial class Location
{
public int Id { get; set; }
public string Name { get; set; }
public string Remark { get; set; }
}
}
I have added new class file which contain the partial class of above file
namespace CRMEntities.Partial_Class
{
public interface ILocation
{
[StringLength(50, ErrorMessage = "Region can accept maximum 50 characters.")]
string Region { get; set; }
[Key]
int Id { get; set; }
[Required]
string Name { get; set; }
string Remark { get; set; }
}
public partial class Location : ILocation
{
}
}
Its giving the below error...
CRMEntities.Partial_Class.Location' does not implement interface member 'CRMEntities.Partial_Class.ILocation.Name
First, you don't need to do this, what I understand is you are trying to do validation right? Think about, the object generated by EF is not ViewModel, they are domain model. Data annotation should be in View Model, not domain model.
Most of cases, often mis-use is to use domain model as view model, but it is not correct much. Because sometime, view models need more than one domain model to provide data for your UI.
So for separation of concerns, you need to define your View Model different with domain model.
Example: you have Location class, you need to add LocationViewModel class and put data annotation in here.
You can map manually or use AutoMapper for mapping bettween View Model and Domain Model.
Another solution is you can use Fluent Validation, with this way, needless to have more partial class just for validation.
You don't show the definition of ILocation in your question, but the error says that the Location.Name property is declared differently than the ILocation.Name member.
Edit: Your two partial classes appear to be in two different namespaces, hence they are actually two entirely different classes, not two parts of the same class. That would explain the compiler error.
Having said that, I do agree with the other answer (+1!) that you should do your UI validation on a view model instead.

Failing to get unobtrusive client validation

I figured out that property i want to be validated has to have [Required] attribute in C#
(am i right?)
If so -my model is linq generated class - how to add this attribute?
You can do it a couple of ways:
If it's possible, make the field non-nullable in the database. This will make the field required at the data layer.
Create a partial class that adds a property to your model class. Use this property instead of the database-generated property.
For example:
public partial class YourEntity
{
[Required]
public string YourNewProperty
{
get { return this.TheRealProperty; }
set { this.TheRealProperty = value; }
}
}
Hopefully this helps
well, you could always make a new class, as a part of a Data access layer, with the same attributes, just put [required] where you want.
I believe your LINQ classes are partials. With MVC, you can use the "MetatDataTypeAttribute"
Like so
[MetadataType(typeof(UserMetadataSource))]
public partial class User {
}
class UserMetadataSource {
[HiddenInput(DisplayValue = false)]
public int UserId { get; set; }
}

MetaData class for entityframework POCO

I am creating a meta data class for a POCO object. I am adding the "CSVColumn" (from LINQToCSV) attribute to the meta data class. But when I run the program, it couldn't find its attributes.
So I tested it using reflection,
Type t = typeof(Case);
PropertyInfo pi = t.GetProperty("ProviderId");
//bool isReadOnly = ReadOnlyAttribute.IsDefined(pi,typeof( ReadOnlyAttribute);
var attributes = pi.GetCustomAttributes(typeof(Case),true);
It acutally return nothing by calling the "GetCustomAttributes".
What have I done wrong??
Below is the way I created metadata class.
One thing I don't understand is, it works perfectly well with MVC validations. Wondering how does that retrieve the custom attributes???
This is the entityframework POCO object
public partial class Case
{
public string ProviderName { get; set; }
public string ProviderId { get; set; }
}
Here I create a partial class of Case and metadata classes,
[MetadataType(typeof(CaseMetaData))]
public partial class Case
{
public class CaseMetaData
{
[CsvColumn(Name = "ProviderName", FieldIndex = 1)]
public string ProviderName { get; set; }
[CsvColumn(Name = "ProviderID", FieldIndex = 2)]
public string ProviderId { get; set; }
}
}
Please someone can help me, much appreciated.
Cheers
typeof(Case) isn't an attribute type.
You mean typeof(CsvColumnAttribute).
Also, standard Reflection isn't aware of metadata classes.
You need to use AssociatedMetadataTypeTypeDescriptionProvider.
A good example can be found here

Using UIHint in combination with LINQ to SQL generated class

I used LINQ to SQL to generate a dbml file which contains the database model for my database table. I want to use UIHint to let MVC present some fields as DropDownLists or Checkboxes in edit mode. But if I change the file, it will be lost if it's been regenerated. How should I solve that issue? I'm quite new to MVC and still learning. I've set up a controller with views for all CRUD elements, but now I'm finetuning and I'm running into this problem.
Since Linq-to-SQL auto-generates partial classes, you'll need to create a partial 'buddy class' where you will add your Data Annotations. Your buddy class mirrors portions of the auto-generated class that you need to modify. You tie them together with [MetadataType(typeof(BuddyClassName))] The partial buddy class and the auto-generated partial class will be merged together when you compile your project.
In an example given that:
Your namespace is "Project.Models"
Your Linq-To-Sql class is called "Products"
using System.ComponentModel.DataAnnotations;
namespace Project.Models
{
[MetadataType(typeof(ProductsMeta))]
public partial class Products
{
// You can extend the products class here if desired.
public class ProductsMeta
{
// This is a Linq-to-Sql Buddy Class
// In here you can add DataAnnotations to the auto-generated partial class
[Key]
public int ProductKey { get; set; }
[Display (Name = "Product Name")]
[Required(ErrorMessage = "Product Name Required")]
[StringLength(255, ErrorMessage = "Must be under 255 characters")]
public string ProductName { get; set; }
[UIHint("MultilineText")]
public string Description { get; set; }
}
}
}
These articles were very helpful:
ScottGu: ASP.NET MVC 2: Model Validation
How to: Validate Model Data Using DataAnnotations Attributes
Validating with Data Annotation Validators
If you are going to use the entities directly you should create a partial class and add your annotations there. This way when the model is regenerated you will not lose your annotations.

Resources