2009-01-19 61 views
16

Tôi muốn đặt thuộc tính trên thuộc tính công khai trong .NET. Tuy nhiên, tôi không có quyền truy cập vào thuộc tính rõ ràng vì đây là mã được tạo trong tệp khác.Thuộc tính liên kết với thuộc tính được tạo mã trong .net

Tôi có lĩnh vực này:

public virtual string Name { get; set; } 

tôi muốn thiết lập này:

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

Lớp học của tôi được đánh dấu là một phần, nhưng bạn không thể có tính chất cục bộ. Tôi nghĩ rằng tôi đã được vào một cái gì đó với lớp MetadataType đó là một tính năng mới của dữ liệu động và DataAnnotations, nhưng than ôi tôi cảm thấy nó chỉ có thể được sử dụng với dữ liệu động, điều này có đúng không?

Trích dẫn: 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

Có cách nào tôi có thể thiết lập này thuộc tính (thậm chí thông qua web.config!) Mà không cần chạm vào lớp mã được tạo?

Cảm ơn trước, Graham

Trả lời

22

Đây là một phiền toái biết; bạn chỉ đơn giản là không thể thêm siêu dữ liệu cho các thành viên được tạo ra.

Có 6 lựa chọn ở đây (theo thứ tự nỗ lực tăng):

  • nếu bạn sở hữu thuộc tính, làm cho nó có thể để khai báo nó chống lại giai cấp, ví dụ: [ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)] - sau đó thêm nhiều thuộc tính cho định nghĩa một phần của lớp
  • sử dụng phương thức ảo/giao diện/etc để truy vấn điều này, thay vì thông qua các thuộc tính
  • phân loại loại được tạo ra; ghi đè hoặc khai báo lại thành viên, thêm siêu dữ liệu (thực sự lộn xộn)
  • sử dụng tùy chỉnh TypeDescriptionProvider để cung cấp siêu dữ liệu động (lô và nhiều công việc) - giả định rằng người tiêu dùng tôn trọng TypeDescriptor; hầu hết người tiêu dùng có liên quan đến ràng buộc thực hiện, nhưng ví dụ: Expression (được nhiều nhà cung cấp LINQ sử dụng) không
  • thay đổi trình tạo mã/viết của riêng bạn
  • cố gắng mở rộng thứ gì đó như PostSharp để thực hiện công việc (Tôi thiên đường không tìm thấy cách để làm điều này, nhưng tôi rất muốn nghe nếu bạn tìm được cách!)

Tôi thường thành công với tùy chọn đầu tiên, trừ khi thuộc tính được hệ thống xác định ([DisplayName], v.v.). Nếu [ValidateNonEmpty] được xác định bởi dữ liệu động, thì bạn có thể không thực hiện được điều này.

+0

Nhờ Marc, Tôi nghĩ đây có thể là trường hợp. Tôi đã quản lý để lặp qua các thuộc tính của lớp được khai báo "MetadataType" của tôi, tại thời điểm tôi muốn hỏi về các thuộc tính, và tôi chỉ đơn giản so sánh tên của thuộc tính "meta" với thuộc tính thực. – GONeale

+0

Nó không giống như yêu cầu các thuộc tính thực sự, tôi hiểu, nhưng đối với những gì tôi cần nó trông giống như nó sẽ phục vụ mục đích trong trường hợp này. Điều đó thật tuyệt. – GONeale

+0

Hy vọng điều này có ý nghĩa. Bây giờ tôi có thể nhìn thấy nếu một thuộc tính xác nhận đã được khai báo và làm việc cho phù hợp. Tôi bây giờ chỉ hy vọng không có chi phí với tôi bằng cách sử dụng lớp thuộc tính 'MetadataType' thay vì làm cho riêng của tôi mà chỉ đơn giản là nói với nó những gì lớp để xem xét các thuộc tính trên. – GONeale

1

Tùy chọn khác là bọc các thuộc tính bên trong các thuộc tính không được tạo trong cùng một lớp. Không lý tưởng bởi vì bạn có thể có các thuộc tính kép nhưng nếu bạn có thể làm cho máy phát điện của bạn tạo ra các thuộc tính được bảo vệ, nó sẽ là một cách tiếp cận khá tốt.

Chỉ cần phải giải quyết vấn đề này: Khung thực thể tạo ra các lớp, tôi muốn tuần tự hóa chúng thành JSON với các tên đơn giản hơn.

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

và add-on lớp:

[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

Kể từ khi lớp học được tạo ra là một lớp học phần, sau đây nên làm việc:

  1. Tạo một giao diện mà có thuộc tính này khai báo trong nó, và trang trí nó với thuộc tính ValidateNonEmpty.
  2. Tạo lớp học một phần của riêng bạn với cùng tên với lớp Tự động tạo và thực hiện việc này triển khai giao diện mà bạn vừa tạo.
  3. bất động sản tại nên được trang trí bằng những thuộc tính mà

Ví dụ:

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

Tôi có ý tưởng này từ geekswithblogs.

+0

Tôi nghĩ rằng sau đó bạn sẽ cần mọi tài sản duy nhất từ ​​lớp cơ sở của bạn cũng đưa vào giao diện, một bài tập tẻ nhạt nếu bạn có nhiều lớp được tạo và nhiều thuộc tính. – secretwep

2

Đây là một giải pháp tuyệt vời, nhưng nó không hoạt động cho vấn đề của tôi. Tôi đang sử dụng EF 6 với các lớp được tạo mã đầu tiên từ cơ sở dữ liệu hiện có. Một trong các cột trong bảng là IDENTITY có giá trị được tạo tự động. Tuy nhiên, lớp từng phần được tạo không cung cấp thuộc tính [DatabaseGenerated (DatabaseGeneratedOption.Identity)] cần để có cơ sở dữ liệu tạo khóa. Kết quả là lỗi "Không thể chèn giá trị rõ ràng cho cột nhận dạng trong bảng 'mytable' khi IDENTITY_INSERT được đặt thành OFF.". Tôi đã thử giải pháp của bạn nhưng nó không hoạt động. Nhưng nếu tôi thêm thuộc tính vào lớp được tạo ban đầu, nó sẽ hoạt động. Vì vậy, tôi vẫn đang cố gắng tìm một giải pháp không yêu cầu sửa đổi tệp được tạo tự động.

Đây là mã tôi đã cố gắng sử dụng giải pháp của bạn:

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

public partial class MyTable : IMyTable 
{ 
} 

gốc tạo ra mã:

[Table("MyTable")] 
public partial class MyTable 
{ 
    [Key] 
    [Column(Order = 1)] 
    public int ID { get; set; } 
} 
Các vấn đề liên quan