自定义合并属性未被Entity Framework迁移生成器识别的解决方案咨询
解决方案:统一自定义属性满足Blazor验证与EF迁移需求
核心思路
通过自定义聚合属性同时实现Blazor表单验证逻辑,并让EF通过约定扫描该属性的配置,自动生成数据库约束,彻底避免重复配置的不一致问题。
步骤1:定义聚合验证属性
创建继承ValidationAttribute的自定义属性,封装所有需要的验证规则(必填、长度、正则等),同时暴露EF需要的元数据(如最大长度、是否必填):
using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class ShortStringFieldAttribute : ValidationAttribute { public int MinLength { get; } = Constants.ShortStringFieldMinLength; public int MaxLength { get; } = Constants.ShortStringFieldMaxLength; public string RegEx { get; } = Constants.ShortNameRegEx; public string DisplayName { get; } public ShortStringFieldAttribute(string displayName) { DisplayName = displayName; } protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { var strValue = value as string; // 必填验证 if (string.IsNullOrEmpty(strValue)) return new ValidationResult($"请输入{DisplayName}"); // 最小长度验证 if (strValue.Length < MinLength) return new ValidationResult($"{DisplayName}长度不能少于{MinLength}个字符"); // 最大长度验证 if (strValue.Length > MaxLength) return new ValidationResult($"{DisplayName}长度不能超过{MaxLength}个字符"); // 正则格式验证 if (!Regex.IsMatch(strValue, RegEx)) return new ValidationResult($"{DisplayName}格式不符合要求"); return ValidationResult.Success; } } // 同理定义长文本字段属性 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class LongStringFieldAttribute : ValidationAttribute { public int MinLength { get; } = Constants.LongStringFieldMinLength; public int MaxLength { get; } = Constants.LongStringFieldMaxLength; public string RegEx { get; } = Constants.LongStringFieldRegEx; public string DisplayName { get; } public LongStringFieldAttribute(string displayName) { DisplayName = displayName; } protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { var strValue = value as string; if (string.IsNullOrEmpty(strValue)) return new ValidationResult($"请输入{DisplayName}"); if (strValue.Length < MinLength) return new ValidationResult($"{DisplayName}长度不能少于{MinLength}个字符"); if (strValue.Length > MaxLength) return new ValidationResult($"{DisplayName}长度不能超过{MaxLength}个字符"); if (!Regex.IsMatch(strValue, RegEx)) return new ValidationResult($"{DisplayName}格式不符合要求"); return ValidationResult.Success; } }
步骤2:配置EF约定识别自定义属性
在DbContext的OnModelCreating方法中,扫描实体属性的自定义属性,自动应用数据库约束:
using Microsoft.EntityFrameworkCore; public class YourDbContext : DbContext { // 定义DbSet... protected override void OnModelCreating(ModelBuilder modelBuilder) { // 遍历所有实体及属性 foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { foreach (var property in entityType.GetProperties()) { // 处理短文本字段属性 var shortAttr = property.PropertyInfo?.GetCustomAttribute<ShortStringFieldAttribute>(); if (shortAttr != null) { property.IsRequired = true; property.SetMaxLength(shortAttr.MaxLength); } // 处理长文本字段属性 var longAttr = property.PropertyInfo?.GetCustomAttribute<LongStringFieldAttribute>(); if (longAttr != null) { property.IsRequired = true; property.SetMaxLength(longAttr.MaxLength); } } } base.OnModelCreating(modelBuilder); } }
步骤3:配置Blazor识别自定义属性的DisplayName
注册自定义IDisplayMetadataProvider,让Blazor表单能读取自定义属性的DisplayName:
// 在Program.cs中添加服务注册 builder.Services.AddSingleton<IDisplayMetadataProvider, CustomDisplayMetadataProvider>(); // 自定义DisplayMetadataProvider实现 using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; public class CustomDisplayMetadataProvider : IDisplayMetadataProvider { public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { var shortAttr = context.Attributes.OfType<ShortStringFieldAttribute>().FirstOrDefault(); if (shortAttr != null) { context.DisplayMetadata.DisplayName = () => shortAttr.DisplayName; } var longAttr = context.Attributes.OfType<LongStringFieldAttribute>().FirstOrDefault(); if (longAttr != null) { context.DisplayMetadata.DisplayName = () => longAttr.DisplayName; } } }
最终使用方式
直接在实体属性上标记自定义属性即可,无需重复添加验证和EF配置:
[ShortStringField("名称")] public string Name { get; set; } = string.Empty; [LongStringField("描述")] public string Description { get; set; } = string.Empty;
这样配置后:
- Blazor表单会自动触发自定义属性内的验证逻辑
- EF迁移时会自动生成
NOT NULL和MAX_LENGTH约束 - 表单会正确显示自定义的DisplayName
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

