I'm trying implement Data Annotation to my Linq to SQL objects. The .dbml file is generated and I'm not sure how to add data annotation to the objects without touching the generated source code.
I tried to add data annotations to the a separate partial class of the object, but its not recognizing it, no Intelli sense either.
As I said in my original answer to this question, you should use an interface. The answer posted after mine (which was marked as Accepted) said to use a class. This is not as good. An interface is a better option for the following reasons:
If there is a mismatch between the name in your LINQ class and the name in your interface, the compiler will flag it for you
An interface can not be instantiated, so this protects class users from accidentally instatntiating the metadata type
If you use Resharper (or similar), the interface can be automatically extracted from the LINQ class
An interface is less verbose than an empty class
If you program against interfaces rather than classes (which is a good practice), then you've already got an interface you can use as your metadata type
For a class called, say "User", create an interface for it (say 'IUser'), and then update the definition of your partial User class as follows:
[MetadataType(typeof(IUser))]
public class User : IUser
Then, in your IUser interface, add appropriate Data Annotation attributes to the properties:
[Required]
[StringLength(50, ErrorMessage = "Username cannot exceed 50 characters")]
string Username { get; set; }
For a class called, say "User", create an interface for it (say 'IUser'), and then update the definition of your partial User class as follows:
[MetadataType(typeof(IUser))]
public class User : IUser
Then, in your IUser interface, add appropriate Data Annotation attributes to the properties:
[Required]
[StringLength(50, ErrorMessage = "Username cannot exceed 50 characters")]
string Username { get; set; }
Linq to SQL generates object classes as partial. An easy way to implement data annotations is to create your own partial class of the object, place the [MetadataType(typeof(YourDataAnnotationClass))] on the partial class you created.
Example:
// Linq to SQL Class
public partial class Article
{
public string Title { get; set; }
...... etc
}
Create your own MetaData class with Metadata for each field you want to validate
public class MyMetaDataClass
{
[Required]
[Range(5,20)]
public string Title { get; set; }
}
Create a Partial Class for the Object class you want to add metadata to, in this case Articles class:
[MetadataType(typeof(MyMetaDataClass))]
public partial class Article { }
Note: you don't need to specify anything in the class, just the metadata type.
Thanks,but the problem is MS define the prototype of MetadataTypeAttrubute as
[AttributeUsageAttribute(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class MetadataTypeAttribute : Attribute
So, you had to use class but not interface
From China
Forest Lee: 李晓强
xiaoqianglinsen#163.com (MSN)
lixiaoqiang#webservice.com.cn
Related
This question already has answers here:
What is ViewModel in MVC?
(16 answers)
Closed 5 years ago.
I have a Account class for account models.
public class Account
{
[Key]
public Int64 UID { get; set; }
[Required]
public string ID { get; set; }
[Required]
public string PassWord { get; set; }
[Required]
public string UserName { get; set; }
}
My project is not a code first project and this is a model class for database 'Account'.
But I use only two properties in login view, string ID and string PassWord.
So I can not use ModelState.Isvalid() in the login controller when I check the validation of model because I use
just two properties...
So I searched about that then, now I found about 'ViewModel' which is the model class for view.
Then I created a new class 'AccountViewModel' and then I mapped this with view instead of 'Account' model.
Did my way was right?
I understood the ViewModel is a model class just for View.
And The model class is for all. (like a global meaning...? for DB,view and so on)
What is different between Model and ViewModel class?
May I get some a nice way to solve this?
As the name says, view model is very specific to the view.It will be a simple POCO with only those properties needed for the view.
Your other model class is your entity models. So if you are using EF code first approach, you need entity class definitions from which EF will generate the database tables. So basically these entity classes look very similar to your db schema structure.
By creating a view model, you are removing the strong coupling of your entity classes to the UI layer. Now your UI layer is independent of your entity classes and if you ever decide to change the data access code from EF to something else, you do not need to touch the views at all.You simply need to update the mapping part(from the view model to the data access/service layer entities)
View models sometimes looks very similar to your entity models, especially if your entity model is a simple table/class.
In your case, since your view is passing a userid and password, you need a simple view model which has only those 2 properties. When user submits the form,you can read the values and use it to build an domain entity class object as needed.
public class LoginViewModel
{
public string UserId { set;get;}
public string Password { set;get; }
}
You can use data annotations with the view models. The MVC model validation framework these data annotations to do the validations. For example, since user should enter a UserId and Password, you may decorate them with appropriate annotations.
public class LoginViewModel
{
[Required]
public string UserId { set;get;}
[Required]
public string Password { set;get; }
}
The [Key] attribute is more useful when you define an entity class. So i would not think it is needed for a view model. Remember view model is more like a UI concern. It has no idea about your underlying data storage mechanism at all.
Some of the most used attributes with view model properties are
Required
MinLength
Range
Url
Phone
StringLength
DataType
So, I have changed my application so that I may use an integer primary key on my tables (a horrid process by the way). Everything works fine. Consider my ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>, IIDentityContext
{
public ApplicationDbContext()
: base("OwinTestDefault")
{
Database.SetInitializer<ApplicationDbContext>(null);
}
...
}
Now consider, for example, my user login class here, in its entirety:
public class CustomUserLogin : IdentityUserLogin<int>
{
}
It seemed silly to have to make a class just for this, and that I should be able to just replace any instance of this with IdentityuserLogin<int> in the code, resulting in this now:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, IdentityUserLogin<int>, CustomUserRole, CustomUserClaim>, IIDentityContext
{
public ApplicationDbContext()
: base("OwinTestDefault")
{
Database.SetInitializer<ApplicationDbContext>(null);
}
...
}
However, bafflingly, it now doesn't work and throws the error:
The type 'Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin`1[System.Int32]' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive or generic, and does not inherit from EntityObject.`
Searching around, some people have run into this when they have changed their table names, but I have not done this, and regardless, overriding OnModelCreating and explicitly mapping everything I can (table name, keys, column names and properties) has no effect and it still complains it isn't mapped. Plus, looking at the source code of the base classes on GitHub, the mapping should be fine anyways.
Any ideas?
It seems that in Entity Framework, you cannot map multiple levels of generic types, as EF cannot create a proxy from this. Props to this answer: Are generic classes not supported as models in Entity Framework?
If you consider IdentityDbContext.cs in the source code, this line:
public virtual IDbSet<TRole> Roles { get; set; }
is really:
public virtual IDbSet<IdentityRole<int, IdentityUserRole<int>> Roles { get; set; }
It needs to be able to make a proxy out of this very type as a whole, thus why using a derived base class works.
I have ignored a column through fluent API but want to populate that property while executing stored procedure using some logic. But it is not mapping the ignored column property. Please let me know if there is any way to do this in Entity framework code first.
I've faced with the same problem recently. The only solution I found is a class hierarchy:
public class MyEntityBase {
public int Id { get; set; }
}
public class MyEntity: MyEntityBase {
...
}//This class is mapped to DB with a fluent API and does not contain ignored property.
//Also it does not have derivative classes, so EF will not create class inheritance in DB.
public class DerivedEntity: MyEntityBase {
public int IgnoredProperty { get; set; }
}//Use this class while executing stored procedures
P.S. Do not mark class MyEntityBase as ABSTRACT - EF will map this relationship as database inheritance.
I have come across a scenerio that to customize DataAnnotations in Dynamic Data Web Application. This is the scenerio:
[Display(Name="DispName")]
public string DName{get;set;}
Instead of hardcoding Name="DispName" for Display DataAnnotation, I want to fetch some value from DataBase and fit int the Name attribute. like:
[Display(Name=SomeValueFromDB)]
public string DName{get;set;}
Is there any way to show the Name attribute of Display DataAnnotation from database instead of hardcoding its value?
Thanks in advance,
Sujith
I found a solution. But this is applicable only if we build the application:
Create a custom class (Say: CustomDisplayNameAttribute ) which inherits DisplayNameAttribute. And call that class name as display attribute (here "CustomDisplayName") above the property name.
While setting DataAnnotation for Display attribute, omit that "Attribute" part from the class name. ie. the DataAnnotation for Display attribute will be CustomDisplayName (not CustomDisplayNameAttribute).
public class DomainClass
{
[CustomDisplayName("")]
public object PropertyName{ get; set; }
}
public class CustomDisplayNameAttribute : DisplayNameAttribute
{
public CustomDisplayNameAttribute(string value)
: base(GetMessageFromResource(value))
{ }
private static string GetMessageFromResource(string value)
{
return "Custom Display Name";
}
}
Hope this helps all....
Happy Coding....
I've a problem when adding metadata to a class named as a reserved keyword. During the generation of the data model (the DBML file), an # has been added to the class name to have it working.
When I apply metadata to the class, it is not working (metadata info is not taken in consideration - the DisplayName and other validation stuff). For all other classes of my project (that do not have a class name as a reserved keyword, it is working). It is currently not possible to rename that class.
Generated class definition:
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.operators")]
public partial class #operator : INotifyPropertyChanging, INotifyPropertyChanged
{...}
MetaData class definition:
[MetadataType(typeof(OperatorMetaData))]
public partial class #operator
{
}
public class OperatorMetaData
{
[DisplayName("Operator Type")]
[Required(ErrorMessage = "Operator type is required.")]
public int operator_type_id { get; set; }
...
}
Anyone any idea how to work around this? Or what did I do wrong ?