簡體   English   中英

.EFCore - 是否可以根據數據庫中的列最大大小創建數據注釋驗證?

[英].EFCore - Is it possible to create data annotation validation based on the column max size in the database?

我不想查看數據庫列定義,而是希望根據數據庫中的列大小進行最大maxlength驗證,這可能嗎?

我問是因為我的一些列是varchar ,有些是nvarchar ,有時會導致混淆,因為對於varchar ,如果max為 100,那么您可以插入 100 個字符,但如果它是最大為 100 的 nvarchar,則可以僅插入 50 個字符.

我想停止這種混亂,這可能嗎?

您可以使用 EF 運行自定義 SQL 查詢以讀取有關表的元信息。 SQL 查詢取決於您使用的實際數據庫。 對於 MySQL,我使用EXPLAIN table來獲取有關表的元信息。 此信息將通過您正在使用的 EF 上下文在名為ExplainInfo的實體中讀取。

對於驗證,您可以創建一個從ValidationAttribute擴展的新驗證類/屬性並覆蓋IsValid(object value, ValidationContext validationContext)方法。 ValidationContext參數很重要,因為我們必須將當前打開的上下文注入驗證器,並獲取有關要驗證的實體類型和屬性名稱的信息。 我們使用它來發送一個查詢,該查詢獲取有關列的信息並針對它驗證當前值。

作為概念驗證,解決方案可能如下所示:

(作為余數, EXPLAIN table的結果如下所示:)

mysql> EXPLAIN Author;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| Id    | int         | NO   | PRI | NULL    | auto_increment |
| Name  | varchar(30) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

首先,我們為EXPLAIN查詢的結果創建一個實體:

public class ExplainInfo
{
    [Key]
    public string Field {get; set;}
    public string Type {get; set;}
}

要使用它,我們必須像往常一樣在上下文中添加一個新的DbSet條目:

public DbSet<ExplainInfo> ExplainInfo {get; set;}

然后我們編寫新的驗證屬性:

public class LimitValidationAttribute : ValidationAttribute
{

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        MyContext context = (MyContext)validationContext.Items["context"];
        string entityName = validationContext.ObjectType.Name;
        string propertyName = validationContext.MemberName;
        IList<ExplainInfo> metaInfo = context.ExplainInfo.FromSqlRaw($"EXPLAIN {entityName}").ToList();
        ExplainInfo singleExplainInfo = metaInfo.Single(it => it.Field == propertyName);
        string databaseType = singleExplainInfo.Type.ToLowerInvariant();
        if (databaseType.StartsWith("varchar("))
        {
            string regexStr = @"varchar\((\d+)\)";
            Regex regex = new Regex(regexStr);
            Match match = regex.Match(databaseType);
            string limitAsString = match.Groups[1].Value;
            int limit = int.Parse(limitAsString);

            string valueAsString = (string)value;
            if (valueAsString.Length > limit) {
                return new ValidationResult("The given value for the property "+propertyName+" exceed the limit of "+limit+" characters defined in the database");
            }
        }
        return ValidationResult.Success;
    }
}

我們將在實體中使用此驗證屬性:

public class Author
{
    // [...]

    [LimitValidation]
    public string Name {get; set;}
    
    // [...]
}

最后我們將觸發驗證:

using (MyContext context = new MyContext())
{
    Author author = context.Author.First();
    ValidationContext validationContext = new ValidationContext(author, new Dictionary<object, object> {
        {"context", context}
    });
    author.Name += "dummy text which will exceed the limit in the database";
    Validator.ValidateObject(author, validationContext, true);
    context.SaveChanges();
}

這將生成以下驗證異常:

屬性名稱的給定值超出了數據庫中定義的 30 個字符的限制

您必須調整VARCHARNVARCHAR類型的IsValid()方法以及獲取表元信息的查詢

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM