.net 部分类中的数据自动化,数据库优先方法

.net 部分类中的数据自动化,数据库优先方法,.net,validation,entity-framework-core,.net,Validation,Entity Framework Core,我喜欢在单独的分部类中定义数据验证的数据自动化,而不是EF生成的分部类。 我尝试在部分类中构建元数据类,如下所示: public partial class PersonViewModel { public string Fname { get; set; } } [MetadataType(typeof(PersonViewModelMetaData))] public partial class PersonViewModel { } public class PersonVie

我喜欢在单独的分部类中定义数据验证的数据自动化,而不是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?}");
            });
        }
    }
}
公共类启动
{
公共启动(IConfiguration配置)
{
配置=配置;
}
公共IConfiguration配置{get;}
//此方法由运行时调用。请使用此方法将服务添加到容器中。
public void配置服务(IServiceCollection服务)
{
services.AddControllersWithViews();
//DI
services.AddDbContext(
option=>option.UseSqlServer(Configuration.GetConnectionString(“xxx”));
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(选项=>
{
option.LoginPath=“/Login”;
}
);
}
//此方法由运行时调用。请使用此方法配置HTTP请求管道。
public void配置(IApplicationBuilder应用程序、IWebHostEnvironment环境)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
其他的
{
app.UseExceptionHandler(“/Home/Error”);
//默认的HSTS值为30天。您可能希望在生产场景中更改此值,请参阅https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(端点=>
{
endpoints.MapControllerRoute(
名称:“默认”,
模式:“{controller=Login}/{action=Index}/{id?}”);
});
}
}
}

公共类程序
{
公共静态void Main(字符串[]args)
{
CreateHostBuilder(args.Build().Run();
}
公共静态IHostBuilder CreateHostBuilder(字符串[]args)=>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder=>
{
webBuilder.UseStartup();
});
}
这是.net核心项目


我错过了什么吗?

据我所知,
MetadataTypeAttribute
在.NETCore中不起作用。查看以获取有关此的更多信息

使用
Microsoft.AspNetCore.Mvc.ModelMetadataType
,而不是使用
Metadata
attributem:

[ModelMetadataType(typeof(PersonViewModelMetaData))]
public partial class PersonViewModel
{
}
这适用于MVC验证,但请记住,如果模型位于不同的程序集中,则不起作用

EF Core的一个解决方案可能是

首先创建一个
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;
}
然后重写
DbContext
SaveChanges
savechangesync
方法:

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();
}

据我所知,
MetadataTypeAttribute
在.NETCore中不起作用。查看以获取有关此的更多信息

使用
Microsoft.AspNetCore.Mvc.ModelMetadataType
,而不是使用
Metadata
attributem:

[ModelMetadataType(typeof(PersonViewModelMetaData))]
public partial class PersonViewModel
{
}
这适用于MVC验证,但请记住,如果模型位于不同的程序集中,则不起作用

EF Core的一个解决方案可能是

首先创建一个
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;
}
然后重写
DbContext
SaveChanges
savechangesync
方法:

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();
}

如果您坚持在.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; }
    }
}

如果您坚持在.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; }
    }
}

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