我试图将数据插入到具有大量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);
所以我添加了以下代码。这解决了这个问题,但是如何在任何db错误,并发,错误的数据类型等方面失败。
try
{
_context.SaveChanges();
}
catch (DbUpdateException e)
{
}
以下不起作用:方法1和方法2:当实现这些时,非空错误不再出现在我们想要的地方。
try
{
_context.SaveChanges();
}
catch (Exception e)
{
}
try
{
_context.SaveChanges();
}
catch
{
}
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等不会为空是很重要的。
您可能会将DbContext的用法包装成一个类,该类隐藏您使用实体框架来保存数据,而不是例如Dapper,或任何更低级别的方法来查询和更新数据。
通常这个包装类被称为Repository
类:Repository
的用户不知道,并且真的不关心,保存数据的方式和位置:SQL?蒙戈?甚至可能是CSV文件?
有一个Repository
类的好处是,如果您决定更改表格布局,或者如果您决定将其中一个查询更改为存储过程,或者如果您决定将数据存储为CSV,则更改将是最小的,用户甚至不会注意到这种变化
在您的存储库中,您将具有查询人员,添加/删除/更新人员等的功能。您之前决定,您的解决方案不应接受具有空名称的人员。
您的解决方案不依赖于数据的保存方式。因此,您的解决方案不应取决于您的存储库是否检查您的名称是否为null或nt。
在调用SaveChanges之前,请考虑检查数据有效性。在这种情况下:检查名字,姓氏等是否确实不为空。你的代码会
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
}
通过使用以下代码,您可以为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
块。