簡體   English   中英

實體框架:如何捕獲任何錯誤

[英]Entity Framework : how to catch any error

我正在嘗試將數據插入具有很多not null約束的SQL Server表中:

CREATE TABLE [dbo].[Customer]
(
    [CustomerId] [int] IDENTITY(1,1) NOT NULL,
    [FirstName] [varchar](255) NOT NULL,
    [LastName] [varchar](255) NOT NULL,
    [AddressLine] [varchar](255) NOT NULL
    CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED ([CustomerId] ASC)
 )

EF代碼:

public virtual DbSet<Customer> Customer { get; set; }
modelBuilder.Entity<Customer>(entity =>
{
    entity.Property(e => e.FirstName)
        .HasMaxLength(255)
        .IsRequired()
        .IsUnicode(false);

    entity.Property(e => e.LastName)
            .HasMaxLength(255)
            .IsRequired()
            .IsUnicode(false);

    entity.Property(e => e.AddressLine)
            .HasMaxLength(255)
            .IsRequired()
            .IsUnicode(false);
  });

嘗試向表中添加數據時,代碼缺少列,因此無法插入數據庫。 我對此並不了解,也沒有收到“ NOT NULL”錯誤,就像我在SQL數據庫中看到的那樣。

var source = new Customer();

source.FirstName = "Joe";  // missing Last Name and Address
_context.Customer.Add(source);

所以我添加了以下代碼。 這解決了問題,但是如果出現任何數據庫錯誤,並發,錯誤的數據類型等,我將如何使它失敗?

try
{
   _context.SaveChanges();
}
catch (DbUpdateException e)
{
}

以下方法不起作用:方法1和2:實現這些方法后,不再出現我們想要的not null錯誤。

try
{
   _context.SaveChanges();
}
catch (Exception e)
{
}


try
{
   _context.SaveChanges();
}
catch
{
}
try {
   var source = new Customer();
   source.FirstName = "Joe";

   _context.Customer.Add(source);
   _context.SaveChanges();
}
catch (Exception ex) {
   // ...
}

您可以在catch塊中檢查異常的類型,以獲取確切的異常消息,例如

try
{
    //Your code here
}
catch (Exception ex)
{
    if (ex.GetType() == typeof(DbEntityValidationException))
    {
        //Exception thrown from System.Data.Entity.DbContext.SaveChanges when validating entities fails.
    }
    else
    if (ex.GetType() == typeof(DbUnexpectedValidationException))
    {
        //Exception thrown from System.Data.Entity.DbContext.GetValidationErrors when an
        //exception is thrown from the validation code.
    }
    else
    {
        //All remaining exception here 
    }
}

或者您可以為每種異常類型使用不同的catch塊

try
{
    //Your code here
}
catch (DbEntityValidationException de_ex)
{
    //Exception thrown from System.Data.Entity.DbContext.SaveChanges when validating entities fails.
}
catch (DbUnexpectedValidationException du_ex)
{
    //Exception thrown from System.Data.Entity.DbContext.GetValidationErrors when an
    //exception is thrown from the validation code.
}
catch (Exception ex)
{
    //All remaining exception here 
}

DbContext.SaveChanges描述了您可能期望的異常。 確定要捕獲的異常,而不要捕獲的異常。

如果不確定在什么情況下會遇到哪些異常,請使用調試器和一些測試代碼來找出您可能期望的異常:

// TODO: create one of your error conditions
try
{
   _context.SaveChanges();
}
catch (Exception e)
{
    Console.WriteLine(e.GetType()); // what is the real exception?
}

當您知道可以預期的異常以及您真正可以處理的異常時,請編寫最終代碼:

try
{
   _context.SaveChanges();
}
catch (DbUpdateException e)
{
    // handle the update exception
}
catch (DbEntityValidationException e)
{
    // handle the entity validation exception
}
catch (...)

您可能不會捕獲System.NotSupportedException,因此您的代碼應僅使用受支持的LINQ語句。

優化

請記住, DbSets中的DbContext代表數據庫中的表。 DbSets的類表示表中的一行:非虛擬屬性表示表中的列,表之間的關系表示為虛擬屬性。

設計這些數據庫表是因為您想解決問題。 顯然,在您的解決方案中,FirstName / LastName等不為null很重要。

您可能會將DbContext的用法包裝到一個類中,該類隱藏了您使用實體框架保留數據的方法,而不是例如Dapper或任何較低級別的方法來查詢和更新數據。

很多時候,這個包裝類被稱為Repository類:你的用戶Repository不知道,真的不關心,您在哪里如何保存你的數據:SQL? 蒙戈? 甚至是CSV文件?

擁有一個Repository類的Repository是,如果您決定更改表布局,或者如果您決定將查詢之一更改為存儲過程,或者如果您決定將數據存儲為CSV,則將最小,用戶甚至不會注意到變化

在您的存儲庫中,您將具有查詢人員,添加/刪除/更新人員等功能。您早先決定解決方案不應接受具有空名稱的人員。

您的解決方案不依賴於如何保存數據。 因此,您的解決方案不應取決於您的存儲庫是否檢查名稱是否為null或nt。

考慮在調用SaveChanges之前檢查數據有效性 在這種情況下:檢查名字,姓氏等是否確實不為空。 您的代碼將

  • 看起來更干凈:您對范圍之外的各方拋出的異常的處理更少
  • 更易於閱讀:讀者不必猜測如果數據為空,會發生什么,
  • 易於測試:您的測試代碼可以使用簡單的模擬存儲庫而無需進行空檢查
  • 更好的可維護性:如果您決定允許添加不帶名字的人,則數據庫模型不會更改,只會更改存儲庫類

通過使用以下代碼,您可以為DbEntityValidationException創建更加用戶友好的消息:

try
{
   _context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
    var sb = new StringBuilder();
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
           sb.AppendLine(string.Format("Property: {0} Error: {1}",
           validationError.PropertyName,validationError.ErrorMessage));
        }
     }
     throw new Exception(sb.ToString(), dbEx);
}

然后,您可以在更高級別捕獲此新的Exception 要捕獲其他異常,可以使用單獨的catch塊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM