【问题标题】:Data automation in partial class, Database first approach部分类中的数据自动化,数据库优先方法
【发布时间】:2021-06-07 04:11:44
【问题描述】:

我喜欢在单独的部分类中定义我的数据自动化以进行数据验证,而不是由 EF 生成的类。 我尝试在部分类中构建元数据类,如下所示:

public partial class PersonViewModel
{
    public string Fname { get; set; }
}

[MetadataType(typeof(PersonViewModelMetaData))]
public partial class PersonViewModel
{
}

public class PersonViewModelMetaData
{
    [Required]
    public string Fname { get; set; }
}

顺便说一句,这个方法不起作用,没有发生数据验证! 我想这可能是因为在启动课程中遗漏了一些东西: 这些是文件:

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            //DI 
           services.AddDbContext<HomeSunSystem>(
            option => option.UseSqlServer(Configuration.GetConnectionString("xxx")));

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(option=>
                {
                    option.LoginPath = "/Login";
                }
                );
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();        
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Login}/{action=Index}/{id?}");
            });
        }
    }
}

 public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();   
                });
    }

这是 .net 核心项目。

我错过了什么吗?

【问题讨论】:

  • data automation 是什么意思?所有的编程都是数据自动化。数据 验证 不由 EF 执行,它是一个单独的 .NET 命名空间,与应用程序堆栈(WinForms、WPF、MVC、Razor、Web API)一起使用。验证器和消息由 UI 而非 EF 显示。 DTO 和模型由堆栈而非 EF 验证。
  • 您的代码包含 no 验证属性或方法。如果要使属性成为必需,请添加 Required 属性。检查Model validation in ASP.NET Core MVC and Razor Pages。验证失败的 DTO 不会自动导致异常,您必须检查其验证状态
  • 实际上,那个部分类不是我的,只是从网上复制它来让你理解我所说的分离元数据的意思。我在我的中使用了 [Required] 和 [MinLentgh(3)] 但它们在实践中不会影响我的数据验证。没有错误但也没有数据验证。
  • 为什么不在 OnModelCreating 中通过 ModelBuilder 使用 Fluent API。这样做您的验证与 Entity 类是分开的。
  • @majid-shahabfar 我知道这是另一种方式。但是为什么这段代码不起作用?

标签: .net validation entity-framework-core


【解决方案1】:

据我所知,MetadataTypeAttribute 在 .NET Core 中不起作用。查看this issue 以获取更多信息。

不要使用Metadata属性,而是使用Microsoft.AspNetCore.Mvc.ModelMetadataType

[ModelMetadataType(typeof(PersonViewModelMetaData))]
public partial class PersonViewModel
{
}

这适用于 MVC 验证,但请记住,如果模型位于不同的程序集中,它就不起作用。

EF Core 的一种解决方法可能是 https://stackoverflow.com/a/49997365/1385614

首先创建一个Mapper类:

public static object MapEntity(object entityInstance)
{
    var typeEntity = entityInstance.GetType();
    var typeMetaDataEntity = Type.GetType(typeEntity.FullName + "MetaData");

    if (typeMetaDataEntity == null)
        throw new Exception();

    var metaDataEntityInstance = Activator.CreateInstance(typeMetaDataEntity);

    foreach (var property in typeMetaDataEntity.GetProperties())
    {
        if (typeEntity.GetProperty(property.Name) == null)
            throw new Exception();

        property.SetValue(
            metaDataEntityInstance,
            typeEntity.GetProperty(property.Name).GetValue(entityInstance));
    }

    return metaDataEntityInstance;
}

然后覆盖DbContextSaveChangesSaveChangesAsync方法:

public override int SaveChanges()
{
    var entities = from e in ChangeTracker.Entries()
        where e.State == EntityState.Added
              || e.State == EntityState.Modified
        select e.Entity;

    foreach (var entity in entities)
    {
        var metaDataEntityInstance = EntityMapper.MapEntity(entity);
        var validationContext = new ValidationContext(metaDataEntityInstance);
        Validator.ValidateObject(
            metaDataEntityInstance,
            validationContext,
            validateAllProperties: true);
    }

    return base.SaveChanges();
}

【讨论】:

  • 感谢您的回复,我会尝试您的建议并让您知道结果。 دمت گرم اقا
  • 欢迎您,测试它,如果它是一个可行的解决方案,那么 با یک آپ ووت ما را خوشحال فرمایید
【解决方案2】:

如果你坚持在 .NET Core 上使用 MetadataType,你可以试试这个:

实体类:

namespace MyProject.Persistence
{
    public partial class User
    {
        public int UserId { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string PasswordHashKey { get; set; }
        public byte Role { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime CreatedUtc { get; set; }
        public DateTime LastUpdateUtc { get; set; }
    }
}

ModelMetadataType:将那些需要验证的属性放在一个接口中,并在一个分部类中从接口驱动实体类。

namespace MyProject.Persistence
{
    [ModelMetadataType(typeof(IUserMetadata))]
    public partial class User : IUserMetadata
    {
        public string FullName => FirstName + " " + LastName;
    }

    public interface IUserMetadata
    {
        [JsonProperty(PropertyName = "Id")]
        int UserId { get; set; }
        [JsonIgnore]
        string Password { get; set; }
        [JsonIgnore]
        string PasswordHashKey { get; set; }
        [JsonIgnore]
        byte Role { get; set; }
    }
}

【讨论】:

    猜你喜欢
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2013-06-22
    • 2012-03-04
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多