2009-01-19 16 views
16

Deseo establecer un atributo en una propiedad pública en .NET; sin embargo, no tengo acceso a la propiedad explícita en sí misma, ya que este ha sido generado en otro archivo.Atributo asociado con propiedad de código generado en .net

tengo este campo:

public virtual string Name { get; set; } 

deseo de establecer esto:

[ValidateNonEmpty("Name is required", ExecutionOrder = 1)] 
public virtual string Name { get; set; } 

Mi clase está marcado como parcial, pero no se puede tener propiedades parciales. Pensé que estaba trabajando en algo con la clase MetadataType, que es una nueva característica de Dynamic Data y DataAnnotations, pero lamentablemente creo que solo se puede usar con Dynamic Data, ¿es así?

Citas: 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

¿Hay alguna manera de poder establecer estos atributos (incluso a través de web.config!) Sin tocar el código generado clase?

Gracias de antemano, Graham

Respuesta

22

Esto es una molestia conocido; simplemente no puede agregar metadatos a los miembros generados.

Hay 6 opciones aquí (en orden creciente de esfuerzo):

  • si posee el atributo, que sea posible declarar en contra de la clase, por ejemplo: [ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)] - a continuación, agregar varios atributos a la definición de clase parcial
  • utilice un método virtual/interfaz/etc para consultar esto, en lugar de a través de los atributos
  • subclase el tipo generado; anula o vuelve a declarar al miembro, agregando los metadatos (realmente desordenado)
  • usa un TypeDescriptionProvider personalizado para proporcionar metadatos dinámicos (muchísimo trabajo), suponiendo que el consumidor respeta TypeDescriptor; la mayoría de los consumidores relacionados vinculantes hacen, pero por ejemplo, Expression (utilizado por muchos proveedores LINQ) no
  • cambio del generador de código/escribir su propia
  • tratar de extender algo así como PostSharp para hacer el trabajo (no he 't encontrado una manera de hacer esto, pero no tengo amor para oír si encuentra una manera!)

por lo general tienen éxito con la primera opción, a menos que sea un atributo definido por el sistema ([DisplayName], etc.) Si [ValidateNonEmpty] está definido por datos dinámicos, es posible que no pueda hacer esto.

+0

Gracias Marc, pensé que esto podría ser el caso:

public interface IMyTable { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] int ID { get; set; } } public partial class MyTable : IMyTable { } 

original de código generado. He logrado iterar a través de las propiedades de mi clase declarada "MetadataType", en el momento en que deseo consultar los atributos, y simplemente comparo el nombre de la propiedad "meta" con la propiedad real. – GONeale

+0

No es lo mismo que consultar los atributos verdaderos, lo entiendo, pero para lo que necesito parece que servirá para el propósito en este caso. Lo cual es genial. – GONeale

+0

Espero que esto tenga sentido. Ahora puedo ver si se declaró un atributo de validación y trabajar en consecuencia. Ahora solo espero que no exista una sobrecarga en la utilización de la clase de atributo 'MetadataType' en lugar de hacer la mía que simplemente le dice en qué clase buscar las propiedades. – GONeale

1

Otra opción es ajustar las propiedades dentro de las propiedades no generadas en la misma clase. No es ideal porque puede terminar teniendo propiedades dobles, pero si puede hacer que su generador haga propiedades protegidas sería un enfoque bastante bueno.

Simplemente tuve que lidiar con este problema: Entity Framework genera clases, quiero serializarlas en JSON con nombres más simples.

// 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; } 
} 

y el add-on de clase:

[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; } 
    } 
} 
6

Desde la clase generada es una clase parcial, el siguiente debería funcionar:

  1. crear una interfaz que tiene esta propiedad declarada en y decorarlo con el atributo ValidateNonEmpty.
  2. Crea tu propia clase parcial con el mismo nombre que la clase AutoGenerated, y haz que implemente la interfaz que acabas de crear.
  3. La propiedad ahora debe ser decorado con ese atributo

Por ejemplo:

// 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; } 
} 

Tengo esta idea de geekswithblogs.

+0

Creo que entonces necesitaría que cada propiedad de su clase base también se coloque en la interfaz, un ejercicio tedioso si tiene muchas clases generadas y muchas propiedades. – secretwep

2

Esta es una gran solución, pero no funcionó para mi problema. Estoy usando EF 6 con clases generadas por código primero de una base de datos existente. Una de las columnas de una tabla es una IDENTIDAD con valores generados automáticamente. Sin embargo, la clase parcial generada no proporcionó el atributo [DatabaseGenerated (DatabaseGeneratedOption.Identity)] necesario para que la base de datos genere la clave. El resultado es el error "No se puede insertar un valor explícito para la columna de identidad en la tabla 'mytable' cuando IDENTITY_INSERT está establecido en OFF.". Probé tu solución pero no funcionó. Pero si agrego el atributo a la clase generada original, funciona. Por lo tanto, todavía estoy tratando de encontrar una solución que no requiera la modificación del archivo generado automáticamente.

Este es el código He intentado utilizar su solución:

[Table("MyTable")] 
public partial class MyTable 
{ 
    [Key] 
    [Column(Order = 1)] 
    public int ID { get; set; } 
} 
Cuestiones relacionadas