实体框架中的验证没有例外

时间:2016-09-12 18:28:40

标签: c# asp.net entity-framework validation domain-driven-design

我正在使用Entity Framework,我想验证我的模型。

示例服务:

var user = _userRepository.GetUser(...);
var order = user.MakeOrder();             //<- this is some business logic in Rich Domain Model
_userRepository.Update(user);
_orderRepository.Add(order);

数据库操作可能会抛出DbEntityValidationException。我可以抓住它并做一些工作来向用户提出错误:

try
{
    _userRepository.Update(user);
    _orderRepository.Add(order);
}
catch(DbEntityValidationException ex)
{
   var error = ex.EntityValidationErrors();
   //Pass errors to Controller
}

但我知道,例外很慢。有没有办法做同样的事情而没有例外(例如某种返回值)以获得更好的性能?

4 个答案:

答案 0 :(得分:2)

1)您必须实现模型IValidatableObject接口,然后在Validate方法

中定义验证规则

Your Model

2-)使用ModelState.IsValid属性。不需要尝试捕获块

Your Api

3-)为页面元素添加验证消息块

ClientSideValitaion

了解更多详情

http://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3

附加

您可以使用流畅的验证 https://fluentvalidation.codeplex.com/wikipage?title=mvc

基本示例http://www.jerriepelser.com/blog/using-fluent-validation-with-asp-net-mvc-part-1-the-basics

答案 1 :(得分:0)

您可以使用DbContext.SaveChanges内部使用的相同方法。它是公开的 - DbContext.GetValidationErrors

  

验证跟踪的实体并返回包含验证结果的DbEntityValidationResult集合。

当然,您应该以某种方式通过您的存储库公开它。

PS 但请注意,事实上这可能会导致性能下降,因为SaveChanges会再次这样做(并注意此方法包含DetectChanges调用,如备注中所述),因为验证错误应该是一个例外情况,可能最好将它们作为例外情况处理,就像在原始代码中一样。

答案 2 :(得分:0)

如果您想避免页面往返,请尝试向模型添加验证并尝试添加客户端验证。使用JQuery验证进行客户端验证以获得更好的性能。

有关客户端验证的更多详细信息。尝试通过以下链接:

  1. http://www.codeproject.com/Articles/718004/ASP-NET-MVC-Client-Side-Validation
  2. http://www.asp.net/mvc/overview/older-versions/getting-started-with-aspnet-mvc4/adding-validation-to-the-model

答案 3 :(得分:-1)

我建议在尝试保存到数据库之前使用内置模型验证。

此示例来自asp.net mvc模板中构建的登录功能。

public class LoginViewModel
{
    [Required]
    [Display(Name = "Email")]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}

然后在控制器中:

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

在视图中:

@using WebApplication1.Models
@model LoginViewModel
@{
    ViewBag.Title = "Log in";
}

<h2>@ViewBag.Title.</h2>
<div class="row">
    <div class="col-md-8">
        <section id="loginForm">
            @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
            {
                @Html.AntiForgeryToken()
                <h4>Use a local account to log in.</h4>
                <hr />
                @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                <div class="form-group">
                    @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
                        @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
                        @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <div class="checkbox">
                            @Html.CheckBoxFor(m => m.RememberMe)
                            @Html.LabelFor(m => m.RememberMe)
                        </div>
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <input type="submit" value="Log in" class="btn btn-default" />
                    </div>
                </div>
                <p>
                    @Html.ActionLink("Register as a new user", "Register")
                </p>
                @* Enable this once you have account confirmation enabled for password reset functionality
                    <p>
                        @Html.ActionLink("Forgot your password?", "ForgotPassword")
                    </p>*@
            }
        </section>
    </div>
    <div class="col-md-4">
        <section id="socialLoginForm">
            @Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { ReturnUrl = ViewBag.ReturnUrl })
        </section>
    </div>
</div>

Html帮助器方法,ValidationMessageFor将使用显示注释中的文本来通知错误。