I have an employee class generated by Entity Framework (EF).
public partial class employee
{
private string name;
public string Name
{
get{return name;}
set{ name = value;}
}
}
Now I want to put a required attribute in the name property to use in for MVC3 validation in another employee partial class which is written by me in order to extend the one which is generated by EF so that I don't have to rewrite my code if I refresh the model generated by EF.
My written partial class is in the same assembly and name space.
public partial class employee
{
// What should I write here to add required attribute in the Name property?
}
It is actually possible only through buddy class but it is not recommended way. You should keep your validation in custom view model because often you need different validations for different views but your entity can keep only single set of validation attributes.
Example of buddy class:
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(EmployeeMetadata))]
public partial class Employee
{
private class EmployeeMetadata
{
[Required]
public object Name; // Type doesn't matter, it is just a marker
}
}
You can't, as far as I'm aware - it's just not feasible.
You should possibly look to see whether MVC3 has any way of adding attributes elsewhere (e.g. to the type) which relate to another property.
Alternatively, you could add a proxying property:
[ValidationAttributesHere]
public string ValidatedName
{
get { return Name; }
set { Name = value; }
}
Another way to do this is:
private class EmployeeMetadata
{
//the type HAS to match what your have in your Employee class
[Required]
public string Name { get; set; }
}
public partial class Employee : EmployeeMetadata
{
}
At least this worked with Linq to SQL. However I had trouble accessing the attributes through GetCustomAttributes (even using System.Attribute.GetCustomAttributes didn't seem to help). Nonetheless MVC did respect those attributes. Additionally this will not work with inheriting from interfaces. Passing attributes from interface will only work using MetadataType class attribute (see answer by Ladislav Mrnka).
Related
I have a class with some properties with DisplayNameEx attribute, which is derived from DisplayNameAttibute:
public class Settings
{
[DisplayNameEx("User")]
public UserData User { get; set; }
}
public class DisplayNameExAttribute : DisplayNameAttribute
{
public DisplayNameExAttribute(string id)
{
}
}
I pass as string id ALLWAYS name of my property, so it would be easier writing code this way:
public class Settings
{
[DisplayNameEx()]
public UserData User { get; set; }
}
Property name I can get here with CallerMemberName attribute:
public class DisplayNameExAttribute : DisplayNameAttribute
{
public DisplayNameExAttribute([CallerMemberName] string propertyName = null)
{
//propertyName I get, what about class name (Settings in my case)?
}
}
Is it possible to get class name also?
It's impossible. Best way in your case is parameter with class name in the constructor of the attribute:
public class DisplayNameExAttribute : DisplayNameAttribute
{
public DisplayNameExAttribute(string className = null)
{
}
}
and then use it like this:
public class Settings
{
[DisplayNameEx("Settings")]
public UserData User { get; set; }
}
I used a similar technique before .NET 4's localizable DisplayAttribute. From .NET 4 I use the DisplayAttribute because it supports localization and it's much more powerful.
I personally would not recommend your idea because of mainly two reasons.
Potential refactoring issues. If one renames your property, he doesn't have any idea that he should also rename the resource with the same name. Same stands for class names. After a few months even you can forget it time to time.
The code is not straightforward. Other developers could not easily understand what your attributes are doing, and even hard to see at first glance that it's related to localization.
I think the best is just to put there those strings.
I've got 2 classes with many different properties and one similar property:
public class A
{
// Lots of specific properties
[Display(Name="Dun and bradstreet number")]
public string DunAndBradstreetNumber {get;set;}
}
public class B
{
// Lots of specific properties
[Display(Name="Dun and bradstreet number")]
public string DunAndBradstreetNumber {get;set;}
}
I realise I have an abundance of choice and I just want to make sure i'm choosing the most semantically correct and popular choice.
1:-----------
Should I declare another class:
public class DunAndBradstreetNumber
{
[Display(Name="Dun and bradstreet number")]
public string DunAndBradstreetNumber {get;set;}
}
and then make class A and B have pointers inside them eg.?
public class A
{
public DunAndBradstreetNumber DunAndBradstreetNumber { get; set; }
}
or
2:-----------
inherit from the DunAndBradstreetNumber?
public class A : DunAndBradstreetNumber
{
//...
}
3:-----------
declare a global function and put that in the get method of each DunAndBradstreetNumber?
public class A
{
public string DunAndBradstreetNumber {
get
{
// Run some function that I may need help on to apply property validation via attributes to
}
set;
}
}
Any more better choices?
My class A and B are domain models using entityframework if that helps at all.
The problem i'm trying to solve is to not have to declare the validation and display attributes twice in different models.
P.S - your opinion is fine... I just want to know the eventualities of the choice I have to make here (albeit its relative insignificance).
I have been looking into DataAnnotations and creating my own DataAnnotations for future use - mainly in MVC4 (which is fairly easy it's safe to say). I want to verify how useful, effective and easy to use they will be if I use the same Model classes in a WPF project.
public class Customer
{
public int Id { get; set; }
[Required()]
public string Name { get; set; }
}
public class ViewModelBase : IDataErrorInfo, INotifyPropertyChanged
{
//... (INotifyPropertyChanged)
public string Error
{
get
{
return string.Empty;
}
}
public string this[string columnName]
{
get
{
//According to tutorials, something here
return string.Empty;
}
}
}
So if I were to move on to creating a CustomerViewModel which inherits from the base class, would I have to present a subset view of the model properties like:
public class CustomerViewModel : ViewModelBase
{
[Required]
public string Name { get; set; }
}
Meaning I have to implement the annotations again, or is it possible to just use the model and somehow reflect model validation back to the front end using WPF's MAGICAL binding?
I have been looking at numerous articles, but none of which seem to be neat or very consice - such as:
http://blog.paulbetts.org/index.php/2010/04/27/wpf-data-validation-using-dataannotations/
Why would you put another Name property in your viemodel?
If you have a Customer property in your viewmodel, you can access it in you xaml like:
{Binding Customer.Name}
This will automatically take your dataanotations from your model class.
Edit: For a good example see: http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM
I have a class I wish to modify the property names of.
However this class is buried about 6 classes deep in a much much larger class(also all custom classes).
My problem is I cant touch any of the existing classes.
The only solution I can think of is to derive from the root class, stick it in a new namespace, then create new classes at each stage inbetween the root class and the class I wanted to modify.
Hopefully this makes sense what Im trying to explain.
Is the above method the only way?
Because you've stated the class you want to extend is a partial class I'm going to recommend that you extend it as such as well. Now you can easily add the new properties, as you've already suggested, and extend the class by adding a class in the same namespace with the same name.
In the example below, both classes are named A and both classes are in the same namespace - those are the two keys to building partial classes.
public partial class A
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}
public partial class A
{
public string PropertyC
{
get
{
var val = this.PropertyA;
// some more functionality maybe...
return val;
}
set
{
// some more functionality maybe...
this.PropertyA = value;
}
}
}
You could create properties with the new names, but keep the old properties there with the [Obsolete] attribute.
Perhaps as compromise you could create additional properties with the new names, then existing code uses the old properties. You could then additionally mark the old attributes as obsolete.
class Example
{
int oldField;
[Obsolete("This is obsolete")]
public int OldField
{
get
{
return this.oldField;
}
set
{
this.oldField = value;
}
}
public int NewField
{
get
{
return this.oldField;
}
set
{
this.oldField = value;
}
}
}
I am extending this DataContext entity, which looks sort'a like this:
namespace Entities
{
public class User
{
public Int32 Id { get; set; }
public String Username { get; set; }
}
}
.. Like so:
public class User : Entities.User
{
new public Int32 Id
{
get { return base.Id; }
}
public void Insert()
{
using (var dc = new DataContext())
{
/*
The "this" keyword should match the type that InsertOnSubmit() expects.
And it does. But I get the following error:
System.NullReferenceException: {"Object reference not set to an instance
of an object."}
*/
dc.Users.InsertOnSubmit(this); // Exception occurs here
dc.SubmitChanges();
}
}
}
I am using the custom User class like so:
var u = new User { Username = "Test" };
u.Insert();
What I don't get is this: I have instantiated the class, so why am I getting a NullReferenceException?
Update:
Extending entity class: overriding a property with an enumerator while still being able to use the "this" keyword on the Insert/Update and DeleteOnSubmit methods on a DataContext instance
enum AccessLevels
{
Basic,
Administrator
}
namespace Entities
{
public class User
{
public Int32 Id { get; set; }
public String Username { get; set; }
public Int32 AccessLevel { get; set; }
}
}
How would I extend or alter the above entity class and implement the AcessLevels enumerator, replacing the AccessLevel property?--this without altering the signature of the entity class, so I'm able to use the "this" keyword on Insert/Update and DeleteOnSubmit methods on a DataContexts.
You can't extend LINQ-to-SQL entity types in this way via inheritance - you should instead use a partial class to add extra methods to the existing generated entity. Because LINQ-to-SQL supports inheritance (for discriminated tables, etc), it expects an exact match to a known entity type - not unexpected subclasses.
i.e.
namespace Entities {
partial class User {
/* your extra method(s) here */
}
}
In the above, this is combined with the partial class in the designer.cs to create you type.
The other way to do this (if partial class isn't an option) is via an extension method.
static class EntityExtensions {
public static void SomeMethod(this User user) {...}
}
If there are methods common between types, you can do this by declaring an interface, using extension methods on that interface, and using partial classes to add the interface to the specific types:
namespace Entities {
partial class User : IFunkyInterface {
/* interface implementation, if necessary */
}
}
static class EntityExtensions {
public static void SomeMethod(this IFunkyInterface obj)
{...}
}
or if you need to know the type:
static class EntityExtensions {
public static void SomeMethod<T>(this T obj)
where T : class, IFunkyInterface
{...}
}
Re the enum edit (added as a second answer to keep things simple)...
Firstly - is there a direct 1:1 mapping between the enum and the values? For example, if Basic is 7 and Administrator is 12, then:
enum AccessLevels
{
Basic = 7,
Administrator = 12
}
Then change the type of that property in the dbml (via the designer) from int to your (fully-qualified) enum: Entities.AccessLevel. LINQ-to-SQL supports enums either as direct integer mappings, or as direct string mappings.
If this isn't possible (more complex scenerios), you can isolate the storage (int) and object-oriented (enum) models; rename the property to AccessLevelStorage (or anything else you like), and in a partial class do the mapping:
partial class User {
public AccessLevel AccessLevel {
get {
switch(AccessLevelStorage) {
case 1: return AccessLevelStorage.Foo;
... etc
default: ...throw an exception?
}
}
set {
switch(value) {
case AccessLevel.Foo: AccessLevelStorage = 1; break;
...etc
default: ...throw an exception?
}
}
}
The only caveat here is that LINQ queries will only work against the storage properties - not the custom mapped property. If you do your queries at the level that declares the context, you can change the access of the storage property to internal - but if you do queries outside of this assembly you'll need to leave is public. You might want to add [Browsable(false)] to stop it appearing in UI models, but that is about it.