Reputation:
I am trying to insert data into a SQL Server table that has a lot of not null
constraints:
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 code:
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);
});
When attempting to add data into table, code is missing columns, so it fails to insert into database. Did not know about this, and did not receive 'NOT NULL' errors, as I would see in SQL database.
var source = new Customer();
source.FirstName = "Joe"; // missing Last Name and Address
_context.Customer.Add(source);
So I added following code. This solves the issue, however how would I have it fail on any db error, concurrency, wrong data types etc.
try
{
_context.SaveChanges();
}
catch (DbUpdateException e)
{
}
Following were not working: Method 1 and 2: When these were implemented, the not null error did not show up anymore as we wanted.
try
{
_context.SaveChanges();
}
catch (Exception e)
{
}
try
{
_context.SaveChanges();
}
catch
{
}
Upvotes: 3
Views: 21653
Reputation: 8171
By using following code you can create a more user friendly message for 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);
}
Then you can catch this new Exception
in higher level; to catching other exceptions you can use separate catch
blocks.
Upvotes: 4
Reputation: 30454
DbContext.SaveChanges describes which exceptions you may expect. Decide which exceptions you want to catch and which ones not.
If you are not certain which exceptions you get in what situations, use your debugger and some test code to find out which exceptions you actually may expect:
// TODO: create one of your error conditions
try
{
_context.SaveChanges();
}
catch (Exception e)
{
Console.WriteLine(e.GetType()); // what is the real exception?
}
When you know which exceptions you a can expect and which ones you really can handle, write your final code:
try
{
_context.SaveChanges();
}
catch (DbUpdateException e)
{
// handle the update exception
}
catch (DbEntityValidationException e)
{
// handle the entity validation exception
}
catch (...)
You probably won't catch System.NotSupportedException, your code should be such that it should only use supported LINQ statements.
Keep in mind that the DbSets
in your DbContext
represent the tables in your database. The classes in the DbSets
represent a row in the table: The non-virtual properties represent the columns in the table, the relations between the tables are represented as virtual properties.
You designed these database tables because you wanted to solve a problem. Apparently in your solution it was important that FirstName / LastName etc would not be null.
You'll probably wrap the usage of your DbContext into a class that hides that you use entity framework to keep your data, instead of, for instance Dapper, or any lower level method to query and update the data.
Quite often this wrapper class is called a Repository
class: users of your Repository
don't know, and really don't care, how and where you save your data: SQL? Mongo? Maybe even a CSV-file?
The nice thing about having a Repository
class is, that if you decide to change your table layout, or if you decide to change one of your queries into a stored procedure, or if you decide to store your data in a CSV, changes will be minimal and users won't even notice the change
In your repository you'll have functions to query Persons, to Add / Delete / Update a Person, etc. You decided earlier that your solution should not accept Persons with null names.
Your solution does not depend on how your data is saved. Hence, your solution should not depend on whether your repository checks whether your names are null or nt.
Consider to check the data validity before calling SaveChanges. In this case: check if first name, last name etc. are indeed not null. Your code will
Upvotes: 10
Reputation: 9771
You can check a type of your exception in catch block to get exact exception message like
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
}
}
Or you can use different catch block per exception type
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
}
Upvotes: 0
Reputation: 155
try {
var source = new Customer();
source.FirstName = "Joe";
_context.Customer.Add(source);
_context.SaveChanges();
}
catch (Exception ex) {
// ...
}
Upvotes: 0