Entity Framework Database First with proper use of Data Anotations - asp.net-mvc-3

I have one project with EF and Code First approach and there using of Data Annotations was straight forward. Now I'm working with Database First and I see that using Data Annotations is more specific so I want to know the right steps to implement it.
The structure of my project that provides Data Access is this:
In ModelExtensions are all my files that I've created to add the Data Annotations to the DbContextModel.tt entities.
Here is the structure of one of my files in ModelExtensions:
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
namespace DataAccess.ModelExtensions
{
[MetadataType(typeof(MCS_ContentTypesMetaData))]
public partial class MCS_ContentTypes : BaseEntity
{
}
internal sealed class MCS_ContentTypesMetaData
{
[Required]
[StringLength(10)]
public string Name { get; set; }
}
}
I have several questions here. First - the namespace. Should it be like this namespace DataAccess.ModelExtensions or I have to remove the .ModelExtensions part. I was looking at a project using DB first and there the namespace was just DataAccess not sure why it is needed (if so). Also - Do I need to add some other references to the DbContextModel.tt entities? Now I use standard C# classes for this and then rename them to : public partial class MCS_ContentTypes : BaseEntity. Do I have to use a special approach for creating those to explicitly expose the connection between the entity and this file?

1) The namespace of your extension models must be the same as the namespace of EF auto-generated entity classes - If the namespace of DbContextModel.tt entity classes is DataAccess, you should set the namespace of your classes to DataAccess.
2) I doesn't get your question completely, however in this approach, names of entity classes and your classes must be the same.
The following example shows what it should be. Suppose that EF generates 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; }
}
}
So, your partial classes should be like the following:
namespace YourSolution
{
[MetadataType(typeof(NewsAttribs))]
public partial class News
{
// leave it empty.
}
public class NewsAttribs
{
// Your attribs will come here.
[Display(Name = "News title")]
[Required(ErrorMessage = "Please enter the news title.")]
public string Title { get; set; }
// and other properties you want...
}
}
So, you doesn't need any : BaseEntity inheritance.

Related

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.

Adding entity frame model to a project

I have problem adding entity framework model to my project. Here is what I am doing:
1- Right click on project
2- Select add
3- In dialog select data from installed templates.
4- in installed template I cannot see ADO.NET entity framework template.
What should I install?
I use NuGet to install Entity framework 4.2.0.0 but no success.
I am using Visual Studio 2010
EDIT: Look for in the comment of answer for information.
Which method of Entity Framework are you trying to use? The most straightforward (in my opinion) is CodeFirst.
DataBaseFirst or ModelFirst
If you are using the wizard to create a model,
Right-click the project > Add New Item
In whichever language you are using, there should be a Data node. Under that node, select ADO.NET Entity Data Model.
Use the designer or wizard to model your ORM mapping
CodeFirst
(you can do this with an existing database, so the name is a bit of a misnomer)
Right-click the project > Add Class
Name it for one of your planned business objects (if using an existing database, classes can be mapped by name if they match tables in the database exactly)
Outline properties (if using an existing database, properties can be mapped by name if they match fields in the database exactly)
Right-Click on the project > Add Library Package Reference
Under Online>All search for Entity, and install the Entity Framework package (if already installed, it may just need to be referenced.
You may need to resolve using statements (or include if using VB.NET) in your entity class(es).
Example
using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.SqlClient;
using System.Data.Common;
namespace Kiersted.Keps.BusinessObjects
{
[Table("Search", Schema = "mySchema")]
public class BatchSearch : KepsBusinessObject, IKepsBusinessObject
{
public BatchSearch() { }
public BatchSearch(DateTime created)
{
this.Created = created;
}
#region Data Properties
[Key]
[Column("BatchSearchID")]
public int SearchId{ get; set; }
[Column("uidQueueMaster")]
public Nullable<int> uidQueueMaster { get; set; }
[Column("DateCreated")]
public DateTime Created { get; set; }
[Column("DateCompleted")]
public Nullable<DateTime> Completed{ get; set; }
public string QueryTerms { get; set; }
[NotMapped]
public string LocalProperty { get; set; }
}
}
Note: If you are using an existing database, you can either name your classes the same as your tables or add the Table attribute to the class declaration. If you are putting your tables into a different schema (default is dbo) then you will need the Table tag regardless of the name so that you can specify the schema.
Note: If you are using and existing database, you can either name your properties the same as the corresponding fields or you can add the Column attribute.

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.

Common DataAnnotations in ASP.Net MVC2

Howdy, I have what should be a simple question. I have a set of validations that use System.CompontentModel.DataAnnotations . I have some validations that are specific to certain view models, so I'm comfortable with having the validation code in the same file as my models (as in the default AccountModels.cs file that ships with MVC2). But I have some common validations that apply to several models as well (valid email address format for example). When I cut/paste that validation to the second model that needs it, of course I get a duplicate definition error because they're in the same namespace (projectName.Models). So I thought of removing the common validations to a separate class within the namespace, expecting that all of my view models would be able to access the validations from there. Unexpectedly, the validations are no longer accessible. I've verified that they are still in the same namespace, and they are all public. I wouldn't expect that I would have to have any specific reference to them (tried adding using statement for the same namespace, but that didn't resolve it, and via the add references dialog, a project can't reference itself (makes sense).
So any idea why public validations that have simply been moved to another file in the same namespace aren't visible to my models?
CommonValidations.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace ProjectName.Models
{
public class CommonValidations
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class EmailFormatValidAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value != null)
{
var expression = #"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]#[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$";
return Regex.IsMatch(value.ToString(), expression);
}
else
{
return false;
}
}
}
}
}
And here's the code that I want to use the validation from:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Growums.Models;
namespace ProjectName.Models
{
public class PrivacyModel
{
[Required(ErrorMessage="Required")]
[EmailFormatValid(ErrorMessage="Invalid Email")]
public string Email { get; set; }
}
}
You have declared EmailFormatValidAttribute as a subclass to CommonValidations. As such you need to reference it like CommonValidations.EmailFormatValidAttribute. Or alternatively move the EmailFormatValidAttribute class out of the CommonValidations class.
This should work:
[CommonValidations.EmailFormatValid(ErrorMessage="Invalid Email")]
public string Email { get; set; }
By the way, you can simplify your class as follows:
public class EmailFormatValidAttribute : RegularExpressionAttribute
{
public EmailFormatValidAttribute() :
base(#"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]#[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$")
{}
}
Also, take a look at this: Data Annotations Extensions. It's a great DataAnnotations library which has already the most common validations included in it.

How do you use Castle Validator with Subsonic generated classes?

Castle Validator uses attributes to specify validation rules. How can you hook these up with Subsonic's generated classes (or any classes where you can't define the attributes on)? Is there a way to programatically specify validation rules without using the attribute method?
I think the best way to do that is using MetadataType.
It's a DataAnnotations that let's your class have like a pair or something like that. I don't know how to explain it better so, let's for the samples:
You first need to add this directive to your code:
using System.ComponentModel.DataAnnotations;
Them you should create the partial class of you generated class with an attribute specifying that this class has an MetadataType:
[MetadataType(typeof(UserMetadata))]
public partial class User
{
}
Then you create your metadata class with your castle validation:
public class UserMetadata
{
[ValidateNonEmpty]
[ValidateLength(6, 24)]
public string Username { get; set; }
[ValidateNonEmpty]
[ValidateLength(6, 100)]
[ValidateEmail]
public string Email { get; set; }
[ValidateNonEmpty]
[ValidateLength(6, 24)]
public string Password { get; set; }
}
There are a few ways to do this - attributes is the lowest friction option, but obviously doesn't deal well with generated code or validation of multiple properties better expressed in code.
Take a look at the following link for some indications on how to do this blog post: Castle Validator Enhancements
If you have a look at the castle source code these are some good starting points:
IValidationContributor interface
DefaultValidationPerformer class

Resources