Thêm chú thích dữ liệu vào một lớp được tạo bởi khung thực thể


93

Tôi có lớp sau được tạo bởi khung thực thể:

public partial class ItemRequest
{
    public int RequestId { get; set; }
    //...

Tôi muốn đặt đây là trường bắt buộc

[Required]
public int RequestId { get;set; }

Tuy nhiên, vì đây là mã được tạo nên nên mã này sẽ bị xóa. Tôi không thể tưởng tượng ra cách tạo một lớp một phần vì thuộc tính được định nghĩa bởi lớp một phần được tạo. Làm cách nào để xác định ràng buộc một cách an toàn?


Nếu thuộc tính của bạn là int, theo mặc định, thuộc tính này là bắt buộc đối với người làm mẫu, vì vậy thuộc tính [Bắt buộc] của bạn sẽ không thêm bất kỳ thứ gì ở đây.
Kirill Bestemyanov

@KirillBestemyanov - @ Html.ValidationMessageFor (model => model.Item.Item.ResourceTypeID) sẽ bị lỗi phía máy khách. Nó không.
P.Brian.Mackey

Câu trả lời:


143

Lớp được tạo ItemRequestsẽ luôn là một partiallớp. Điều này cho phép bạn viết một lớp từng phần thứ hai được đánh dấu bằng các chú thích dữ liệu cần thiết. Trong trường hợp của bạn, lớp một phần ItemRequestsẽ trông như thế này:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

//make sure the namespace is equal to the other partial class ItemRequest
namespace MvcApplication1.Models 
{
    [MetadataType(typeof(ItemRequestMetaData))]
    public partial class ItemRequest
    {
    }

    public class ItemRequestMetaData
    {
        [Required]
        public int RequestId {get;set;}

        //...
    }
}

11
Lớp một phần sẽ không được tạo lại. Đó là lý do tại sao nó được định nghĩa là một phần.
MUG4N

bạn đã bỏ lỡ công cụ sửa đổi một phần? Bạn có sử dụng cùng một không gian tên không?
MUG4N

3
Người dùng .NET Core: sử dụng ModelMetadataType thay vì MetadataType.
Bob Kaufman

1
Bạn có thể đặt các partial class bất cứ nơi nào bạn muốn miễn là không gian tên là giống hệt nhau
MUG4N

40

Như MUG4N đã trả lời, bạn có thể sử dụng các lớp từng phần nhưng thay vào đó sẽ tốt hơn khi sử dụng giao diện . Trong trường hợp này, bạn sẽ gặp lỗi biên dịch nếu mô hình EF không tương ứng với mô hình xác thực. Vì vậy, bạn có thể sửa đổi các mô hình EF của mình mà không sợ rằng các quy tắc xác thực đã lỗi thời.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace YourApplication.Models
{
    public interface IEntityMetadata
    {
        [Required]
        Int32 Id { get; set; }
    }

    [MetadataType(typeof(IEntityMetadata))]
    public partial class Entity : IEntityMetadata
    {
        /* Id property has already existed in the mapped class */
    }
}

PS Nếu bạn đang sử dụng loại dự án khác với ASP.NET MVC (khi bạn thực hiện xác thực dữ liệu thủ công), đừng quên đăng ký trình xác thực của bạn

/* Global.asax or similar */

TypeDescriptor.AddProviderTransparent(
    new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Entity), typeof(IEntityMetadata)), typeof(Entity));

@dimonser giải pháp tốt, tôi đã thử thêm các nhận xét xml như thế này (đối với những trường DB cần giải thích một chút trong mã - tức là được hiển thị trong intellitype) nhưng nó có vẻ không hoạt động. Có ý tưởng nào để làm việc này không?
Percy

Xin chào @Rick, bạn có thể đặt nhận xét về thuộc tính giao diện, nhưng bạn sẽ chỉ thấy nhận xét đó khi bạn làm việc với biến giao diện. Hoặc bạn có thể đặt một nhận xét trong một lớp học. Trong trường hợp này, bạn sẽ thấy nó khi bạn làm việc với một thể hiện của lớp mình. Không có trường hợp nào khác. Vì vậy, bạn có thể sử dụng cả trong số họ để trang trải tất cả các tình huống, Trong trường hợp đầu tiên, bạn có thể mô tả quy tắc xác nhận hiện trường và trong trường hợp thử thứ hai để mô tả mục đích
dimonser

Thực sự đã nghĩ ra câu trả lời, nhưng sở thích của tôi là thấy lỗi biên dịch nếu xác thực không còn đồng bộ với lớp khung thực thể được tạo tự động. Tôi đang đấu tranh để nghĩ về một tình huống mà bạn có thể muốn xác thực một thuộc tính không còn tồn tại trong lớp khung thực thể của bạn.
Mike

1
Đây không phải làm việc đối với tôi, nó nói tôi cần phải thực hiện các giao diện IEntityMetadata ...
Worthy7

14

Tôi đã tìm thấy một giải pháp giống như câu trả lời của MUG4N , nhưng thay vào đó, lồng MetaDatalớp trong lớp thực thể, do đó giảm số lượng lớp trong danh sách không gian tên công khai của bạn và loại bỏ sự cần thiết phải có tên duy nhất cho mỗi lớp siêu dữ liệu.

using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models 
{
    [MetadataType(typeof(MetaData))]
    public partial class ItemRequest
    {
        public class MetaData
        {
            [Required]
            public int RequestId;

            //...
        }
    }
}

Tôi đã sử dụng điều này trong tất cả dự án của mình. Dễ dàng tổ chức hơn nhiều. Tôi cũng thêm các thuộc tính tùy chỉnh bằng cách sử dụng [NotMapped]bên trong lớp một phần khi tôi cần chúng.
Carter Medlin

5

Đây là phần mở rộng cho câu trả lời @dimonser nếu bạn tạo lại mô hình db của mình, bạn sẽ phải thêm lại các giao diện trên các lớp đó theo cách thủ công.

Nếu bạn có hứng thú với nó, bạn cũng có thể sửa đổi các .ttmẫu của mình :

Đây là ví dụ về giao diện tự động tạo trên một số lớp, đây là phân đoạn từ phương thức .ttchỉ thay thế EntityClassOpeningtrong phương thức của bạn với sau (và rõ ràng là var stringsToMatchvới tên thực thể và giao diện của bạn).

public string EntityClassOpening(EntityType entity)
{
    var stringsToMatch = new Dictionary<string,string> { { "Answer", "IJourneyAnswer" }, { "Fee", "ILegalFee" } };
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}{4}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)),
        stringsToMatch.Any(o => _code.Escape(entity).Contains(o.Key)) ? " : " + stringsToMatch.Single(o => _code.Escape(entity).Contains(o.Key)).Value : string.Empty);
}

Tuy nhiên, không một người bình thường nào nên làm điều này với chính mình, điều này đã được chứng minh trong Kinh thánh rằng một người sẽ xuống Địa ngục vì điều này.


2

Tôi không chắc làm thế nào để làm những gì bạn đang yêu cầu nhưng có một cách xung quanh nó. Xác thực dữ liệu động bằng cách ghi đè GetValidators của DataAnnotationsModelValidatorProvider tùy chỉnh của bạn. Trong đó, bạn có thể đọc các quy tắc xác thực từng trường (từ cơ sở dữ liệu, tệp cấu hình, v.v.) và thêm trình xác thực nếu cần. Nó có các giá trị bổ sung mà xác thực của bạn không còn được kết hợp chặt chẽ với mô hình và có thể được thay đổi mà không cần khởi động lại trang web. Tất nhiên nó có thể là quá mức cần thiết cho trường hợp của bạn, nhưng nó là lý tưởng cho trường hợp của chúng tôi!


Chúng tôi đã làm khi lần đầu tiên triển khai cấu trúc này. Kể từ đó, chúng tôi đã chuyển sang NHibernate, nhưng điều này không liên quan đến giải pháp. Mã xác nhận của chúng tôi hoạt động như bình thường mà không có thay đổi nào (chỉ có lớp truy cập dữ liệu được thay đổi).
JTMon

1

Sửa đổi mẫu T4 thêm các chú thích bắt buộc, tệp này thường có tên MODELNAME.tt

tìm nơi T4 đang tạo lớp và các phương thức để biết nơi đặt chúng.

     <#=codeStringGenerator.IgnoreJson(navigationProperty)#>


//create this method in file
public string IgnoreJson(NavigationProperty navigationProperty){
            string result = navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? "" : @"[JsonIgnore]
    [IgnoreDataMember]";

            return result;
        }

Bạn cũng sẽ cần thêm không gian tên;

<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using System.Runtime.Serialization;

Xây dựng lại các lớp của bạn bằng cách lưu mô hình của bạn, tất cả các phương thức của bạn phải được chú thích.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.