Reputation: 26484
I wish to set an attribute on a public property in .NET, however I do not have access to the explicit property itself, as this has been code generated in another file.
I have this field:
public virtual string Name { get; set; }
I wish to set this:
[ValidateNonEmpty("Name is required", ExecutionOrder = 1)]
public virtual string Name { get; set; }
My class is marked as partial, but you cannot have partial properties. I thought I was on to something with the MetadataType class which is a new feature of Dynamic Data and DataAnnotations, but alas I feel it can only be used with Dynamic Data, is this true?
Citations: http://blogs.oosterkamp.nl/blogs/jowen/archive/2008/10/16/metadatatype-attribute.aspx http://blogs.msdn.com/davidebb/archive/2008/06/16/dynamic-data-and-the-associated-metadata-class.aspx
Is there any way I can set this attributes (even through web.config!) without touching the code generated class?
Thanks in advance, Graham
Upvotes: 18
Views: 5144
Reputation: 21
This is a great solution, but it didn't work for my problem. I'm using EF 6 with code-first generated classes from an existing database. One of the columns in a table is an IDENTITY with auto generated values. However, the generated partial class did not provide the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute needed to have the database generate the key. The result is the error "Cannot insert explicit value for identity column in table 'mytable' when IDENTITY_INSERT is set to OFF.". I tried your solution but it didn't work. But if I add the attribute to the original generated class, it does work. So I'm still trying to find a solution that does not require the modifying of the auto generated file.
Here is the code I tried using your solution:
public interface IMyTable
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
int ID { get; set; }
}
public partial class MyTable : IMyTable
{
}
original generated code:
[Table("MyTable")]
public partial class MyTable
{
[Key]
[Column(Order = 1)]
public int ID { get; set; }
}
Upvotes: 2
Reputation: 150
Since the generated class is a partial class, the following should work:
For example:
// Decorate the properties with attributes as required
public interface IMyInterface
{
[ValidateNonEmpty("Name is required")]
string Name { get; set; }
}
// This is the partial class I created, that implements the interface
public partial class MyGeneratedClass : IMyInterface
{
}
// This is the auto-generated class
public partial class MyGeneratedClass
{
public virtual string Name { get; set; }
}
I got this idea from geekswithblogs.
Upvotes: 6
Reputation: 11040
Another option is to wrap the properties inside non-generated properties in the same class. Not ideal because you may end up having double properties but if you can make your generator make protected properties it'd be a pretty good approach.
Just had to deal with this problem: Entity Framework generates classes, I want to serialize them to JSON with simpler names.
// GENERATED BY EF
public partial class ti_Users
{
public ti_Users()
{
this.ti_CardData = new HashSet<ti_CardData>();
this.ti_Orders = new HashSet<ti_Orders>();
}
protected int userId { get; set; }
protected string userName { get; set; }
protected string userEmail { get; set; }
protected string userPassHash { get; set; }
protected Nullable<System.DateTime> userLastLogin { get; set; }
protected string userLastIP { get; set; }
public virtual ICollection<ti_CardData> ti_CardData { get; set; }
public virtual ICollection<ti_Orders> ti_Orders { get; set; }
}
and the add-on class:
[JsonObject(memberSerialization: MemberSerialization.OptIn)]
public partial class ti_Users
{
[JsonProperty]
public int UserId
{
get { return this.userId; }
set { this.userId = value; }
}
[JsonProperty]
public string Name
{
get { return this.userName; }
set { this.userName = value; }
}
[JsonProperty]
public string Email
{
get { return this.userEmail; }
set { this.userEmail = value; }
}
[JsonProperty]
public string PassHash
{
get { return this.userPassHash; }
set { this.userPassHash = value; }
}
}
Upvotes: 1
Reputation: 1064044
This is a known nuisance; you simply can't add metadata to the generated members.
There are 6 options here (in order of increasing effort):
[ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)]
- then add multiple attributes to the partial class definitionTypeDescriptionProvider
to provide dynamic metadata (lots and lots of work) - assuming that the consumer respects TypeDescriptor
; most binding-related consumers do, but for example, Expression
(used by many LINQ providers) doesn'tI usually have success with the first option, unless it is a system-defined attribute ([DisplayName]
, etc). If [ValidateNonEmpty]
is defined by dynamic data, then you might not be able to do this.
Upvotes: 23