【问题标题】:Exception handling in Entity Framework实体框架中的异常处理
【发布时间】:2013-11-16 05:19:10
【问题描述】:

我有一个表单,它有一些字段并且与数据库有关系。我正在使用实体框架,我想在 sql server 发送错误消息之前处理异常。例如,当用户在 sql server 处理之前在数字字段中输入字符串值或 web 应用程序处理异常时。我写了这段代码,但它不适用于所有异常。例如,如果字段为空或类型无效,则表示输入字符串的格式不正确。

 using (var context  = new entityTestEntities2())
        {
            try
            {
                int stNumber = Convert.ToInt32(textBox2.Text);
                var allCustomers = context.setcust(null, stNumber);
            }
            catch(Exception ex)
            {
                if (ex.Message.Contains("correct format"))
                { 
                int x= System.Runtime.InteropServices.Marshal.GetExceptionCode();
                     MessageBox.Show("error number"+x.ToString()+ex.Message);
                }
             }
        } 

【问题讨论】:

  • 我推荐 Integer.TryParse 从文本框输入。
  • 我的问题很笼统,它只是一个例子(int 或空字段)
  • 用户界面是什么样的?我们最近经常使用 MVC3,我们将使用属性构建数据模型和/或使用不显眼的 javascript 验证。我认为您希望在更接近 UI 的地方进行验证,而不是让它调用数据库,尤其是在 Web 环境中。
  • 我在 web 应用程序中使用 java 脚本执行此操作,但我想生成核心并将异常句柄放在核心中。我想找到解决方案
  • EF 中的验证:msdn.microsoft.com/en-gb/data/gg193959.aspx MVC 使用实体上的数据注释来支持 jQuery 不显眼的验证 stackoverflow.com/questions/11534910/…

标签: c# asp.net entity-framework c#-4.0


【解决方案1】:

您应该首先在 UI 上进行验证,然后处理与实体框架相关的特定错误。

创建模型并使用数据注释:

using System.ComponentModel.DataAnnotations;
public class YourViewModel
    {
        [Required]
        [Range(0, 15, ErrorMessage = "Can only be between 0 .. 15")]
        public int stNumber { get; set; }
    }

在您的控制器中将模型返回到视图:

var model = new YourViewModel();
return View(model);

通过将模型添加到视图并使用一些标签助手将文本框绑定到模型:

@using YourProject.WebUI.Models
@model YourViewModel  

@Html.TextBoxFor(m => m.stNumber )
@Html.ValidationMessageFor(m => m.stNumber )

现在,当有人尝试输入非数字或超出范围的数字时,将向用户显示错误,然后再将错误数据发送回控制器。

要处理实体框架异常,请使用 try catch:

        try
        {
            var entity = context.yourEntity.FirstOrDefault(o => o.Id == custId);

            if (entity == null) return false;
            entity.value= stNumber;
            entity.ModifiedBy = userId;
            entity.ModifiedDate = DateTime.Now;
            Db.SaveChanges();
            return true;
        }
        catch (DbUpdateException Ex)
        {
            Console.WriteLine(ex.InnerException.Message);
            return false;
        }

其他异常类型包括:

DbUpdateException

向数据库发送更新时出错。

DbUpdateConcurrencyException

数据库命令没有影响预期的行数。这通常表示乐观并发违规;也就是说,数据库中的一行自从被查询后发生了变化。

DbEntityValidationException

由于实体属性值验证失败,保存被中止。

NotSupportedException

尝试使用不受支持的行为,例如在同一个上下文实例上同时执行多个异步命令。

ObjectDisposedException

上下文或连接已被释放。

InvalidOperationException

在向数据库发送命令之前或之后尝试处理上下文中的实体时发生了一些错误。

【讨论】:

    【解决方案2】:

    您应该捕获 SqlException,而不是捕获 Exception。

    SqlException 有一个可以使用的数字属性:

    catch (SqlException e)
    {
       MessageBox.Show("Error number: "+e.Number + " - " + e.Message);
    }
    

    【讨论】:

      【解决方案3】:

      您应该做的是找到适合您的解决方案模型的架构。一般来说,我会在创建上下文之前进行验证。如果您需要在应用程序中进行更多验证,您可能需要为此创建一个验证层。

      public class RuleViolation
      {
          public string Property {get; set;}
          public string Message {get; set;}
      }
      
      public class Program
      {
          public static List<RuleViolation> GetRuleViolations(string[] parameters)
          {
              List<RuleViolation> validations = new List<RuleViolation>();
      
              if(!int.TryParse(parameters[0], out new Int32()))
              {
                  validations.Add(new RuleViolation{Message ="Input1 must be integer.", Property = "input1"});
              }
              //more validation
      
              return validations;
          }
      
          public static void Main(string[] parameters)
          {
              var validations = GetRuleViolations(parameters);
      
              if(validations.Any())
              {
                  validations.ForEach(x=> Console.WriteLine(x.Message));
                  return;
              }
      
              int input1 = int.Parse(parameters[0]);
      
              //after all your business logic are ok, then you can go to persistence layer to hit the database.
              using (var context  = new entityTestEntities2())
              {
                  try
                  {
                      var allCustomers = context.setcust(null, input1);
                  }
                  catch(SqlException exc)
                  {
                      //here you might still get some exceptions but not about validation.
      
                      ExceptionManager.Log(exc);
      
                      //sometimes you may want to throw the exception to upper layers for handle it better over there!
                      throw;
                  }
              }
          }
      }
      

      希望该示例使有关验证逻辑的体系结构更加清晰。

      【讨论】:

        猜你喜欢
        • 2013-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-27
        • 2016-05-22
        • 1970-01-01
        • 1970-01-01
        • 2013-05-12
        相关资源
        最近更新 更多