MVC模型验证从数据库 [英] MVC Model Validation From Database

查看:231
本文介绍了MVC模型验证从数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的模型,需要从数据库中获取验证

I have a very simple Model, that needs to get validated from Database

public class UserAddress
{
    public string CityCode {get;set;}
}

城市code 可以拥有只在我的数据库表中可用的值。

CityCode can have values that are only available in my database table.

我知道我可以做这样的事情。

I know i can do something like.

[HttpPost]
public ActionResult Address(UserAddress model)
{
    var connection = ; // create connection
    var cityRepository = new CityRepository(connection);

    if (!cityRepository.IsValidCityCode(model.CityCode))
    {
        // Added Model error
    }
}

这似乎很 WET ,因为我必须使用这种模式在很多放置,并添加同样的逻辑每个地方好像我不使用MVC架构正常。

This seems very WET as I have to use this model at lot of placed and adding the same logic each place seems like i am not using MVC Architecture properly.

那么,什么是从数据库?验证模型的最佳模式

注意: 大部分的验证都是单场查询从数据库,其他验证包括场组合。但现在我很高兴与单场查询验证,只要是并没有使用太多的思考是可以接受的。

NOTE: Most of the validation are single field lookup from Database, other validation may include combination of field. But right now I am happy with single field lookup validation, as long as it is DRY and is not using too much reflection it is acceptable.

无客户端验证: 应用于任何人谁是回答在客户端验证而言,我不需要任何这样的验证,我的大部分验证是服务器片面的,而我需要的是相同的,请不要使用客户端验证方法回答。

P.S。如果任何一个可以给我提示如何从数据库做一个属性的验证,将是非常感激。

P.S. If any one can give me hint how to do a attribute based validation from Database, will be extremely greatful.

推荐答案

请检查修改从附着从这个答案的中间,为更详细和通用的解决方案。


Please check the EDIT from attached from the middle of this answer, for more elaborate and generic solution.

以下是我的解决方案做基础的验证一个简单的属性。创建一个属性 -

Following is my solution to do a simple Attribute based Validation. Create an attribute -

public class Unique : ValidationAttribute
{
    public Type ObjectType { get; private set; }
    public Unique(Type type)
    {
        ObjectType = type;
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (ObjectType == typeof(Email))
        {
            // Here goes the code for creating DbContext, For testing I created List<string>
            // DbContext db = new DbContext();
            var emails = new List<string>();
            emails.Add("ra@ra.com");
            emails.Add("ve@ve.com");

            var email = emails.FirstOrDefault(u => u.Contains(((Email)value).EmailId));

            if (String.IsNullOrEmpty(email))
                return ValidationResult.Success;
            else
                return new ValidationResult("Mail already exists");
        }

        return new ValidationResult("Generic Validation Fail");
    }
}

我创建了一个简单的模型来测试 -

I created a simple model to test -

public class Person
{
    [Required]
    [Unique(typeof(Email))]
    public Email PersonEmail { get; set; }
    [Required]
    public GenderType Gender { get; set; }
}

public class Email
{
    public string EmailId { get; set; }
}

然后,我创建了如下的观点 -

Then I created following View -

@model WebApplication1.Controllers.Person
@using WebApplication1.Controllers;

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

@using (Html.BeginForm("CreatePersonPost", "Sale"))
{
    @Html.EditorFor(m => m.PersonEmail)

    @Html.RadioButtonFor(m => m.Gender, GenderType.Male) @GenderType.Male.ToString()
    @Html.RadioButtonFor(m => m.Gender, GenderType.Female) @GenderType.Female.ToString()
    @Html.ValidationMessageFor(m => m.Gender)

    <input type="submit" value="click" />
}

现在当我输入相同的电子邮件 - ra@ra.com 并点击提交按钮,我可以在我的 POST 动作,如下图所示。

Now When I enter the same Email - ra@ra.com and click on Submit button I can get errors in my POST action, as shown below.

修改这里去更通用的,详细的解答。

EDIT Here goes more generic and detailed answer.

创建 IValidatorCommand -

public interface IValidatorCommand
{
    object Input { get; set; }
    CustomValidationResult Execute();
}

public class CustomValidationResult
{
    public bool IsValid { get; set; }
    public string ErrorMessage { get; set; }
}

让我们假设,我们有我们的的UnitOfWork 中这样定义 -

Lets assume we have our Repository and UnitOfWork defined in following way -

public interface IRepository<TEntity> where TEntity : class
{
    List<TEntity> GetAll();
    TEntity FindById(object id);
    TEntity FindByName(object name);
}

public interface IUnitOfWork
{
    void Dispose();
    void Save();
    IRepository<TEntity> Repository<TEntity>() where TEntity : class;
} 

现在让创建了自己的验证命令 -

Now lets created our own Validator Commands -

public interface IUniqueEmailCommand : IValidatorCommand { }

public interface IEmailFormatCommand : IValidatorCommand { }

public class UniqueEmail : IUniqueEmailCommand
{
    private readonly IUnitOfWork _unitOfWork;
    public UniqueEmail(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    public object Input { get; set; }

    public CustomValidationResult Execute()
    {
        // Access Repository from Unit Of work here and perform your validation based on Input
        return new CustomValidationResult { IsValid = false, ErrorMessage = "Email not unique" };
    }
}

public class EmailFormat : IEmailFormatCommand
{
    private readonly IUnitOfWork _unitOfWork;
    public EmailFormat(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    public object Input { get; set; }

    public CustomValidationResult Execute()
    {
        // Access Repository from Unit Of work here and perform your validation based on Input
        return new CustomValidationResult { IsValid = false, ErrorMessage = "Email format not matched" };
    }
}

创建了校验器厂这将给我们的基础上选择一个特定的命令。

Create our Validator Factory which will give us a particular command based on Type.

public interface IValidatorFactory
{
    Dictionary<Type,IValidatorCommand> Commands { get; }
}

public class ValidatorFactory : IValidatorFactory
{
    private static Dictionary<Type,IValidatorCommand> _commands = new Dictionary<Type, IValidatorCommand>();

    public ValidatorFactory() { }        

    public Dictionary<Type, IValidatorCommand> Commands
    {
        get
        {
            return _commands;
        }
    }

    private static void LoadCommand()
    {
        // Here we need to use little Dependency Injection principles and
        // populate our implementations from a XML File dynamically
        // at runtime. For demo, I am passing null in place of UnitOfWork
        _commands.Add(typeof(IUniqueEmailCommand), new UniqueEmail(null));
        _commands.Add(typeof(IEmailFormatCommand), new EmailFormat(null));
    }

    public static IValidatorCommand GetCommand(Type validatetype)
    {
        if (_commands.Count == 0)
            LoadCommand();            

        var command = _commands.FirstOrDefault(p => p.Key == validatetype);
        return command.Value ?? null;
    }
}

和装修的验证属性 -

And the renovated Validation Attribute -

public class MyValidateAttribute : ValidationAttribute
{
    public Type ValidateType { get; private set; }
    private IValidatorCommand _command;
    public MyValidateAttribute(Type type)
    {
        ValidateType = type;            
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        _command = ValidatorFactory.GetCommand(ValidateType);
        _command.Input = value;
        var result = _command.Execute();

        if (result.IsValid)
            return ValidationResult.Success;
        else
            return new ValidationResult(result.ErrorMessage);
    }
}

最后,我们可以用我们的属性如下: -

Finally we can use our attribute as follows -

public class Person
{
    [Required]
    [MyValidate(typeof(IUniqueEmailCommand))]
    public string Email { get; set; }
    [Required]
    public GenderType Gender { get; set; }
}

输出如下 -

Output as follows -

修改详细说明,使该解决方案更加通用。

EDIT Detailed explanation to make this solution more generic.

可以说,我有一个属性电子邮件,我需要做以下检验 -

Lets say I have a property Email where I need to do following validations -

  1. 格式
  2. 长度
  3. 唯一

在这种情况下,我们可以创建 IEmailCommand IValidatorCommand 继承。然后继承 IEmailFormatCommand IEmailLengthCommand IEmailUniqueCommand IEmailCommand

In that case we can create IEmailCommand inherited from IValidatorCommand. Then inherit IEmailFormatCommand, IEmailLengthCommand and IEmailUniqueCommand from IEmailCommand.

我们的 ValidatorFactory 将持有的全部三个命令实现的池词典&LT;类型,IValidatorCommand&GT;命令

Our ValidatorFactory will hold the pool of all three command implementations in Dictionary<Type, IValidatorCommand> Commands.

现在,而不是装饰我们的电子邮件属性有三个命令,我们可以用 IEmailCommand 装饰它。

Now instead of decorating our Email property with three commands, we can decorate it with IEmailCommand.

在这种情况下,我们的 ValidatorFactory.GetCommand()方法需要改变。相反,每次返回一个命令,它应该返回所有匹配的命令为特定类型。所以基本上它的签名应该是名单,其中,IValidatorCommand&GT; GetCommand(类型validatetype)

In this case, our ValidatorFactory.GetCommand() method needs to be changed. Instead of returning one command every time, it should return all matching commands for a particular type. So basically its signature should be List<IValidatorCommand> GetCommand(Type validatetype).

现在,我们可以得到所有与房地产相关的命令,我们可以循环的命令,并得到验证结果在我们的 ValidatorAttribute

Now as we can get all the commands associated with a property we can loop the commands and get the Validation results in our ValidatorAttribute.

这篇关于MVC模型验证从数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆