Entity Framework Core DbUpdateException detailed information

c# entity-framework-core integration-testing

Question

I am just getting started with EF Core in my full .net 4.5.2 project and am trying to do an integration test to validate I can insert a new student.

The issue is, I want to be able to get better information from the exception being thrown as to why it is not inserting into the database.

Here is my integration test code:

    [Fact]
    public void save_the_new_student_to_the_database()
    {
        var fixture = new Fixture();
        var optionsBuilder = new DbContextOptionsBuilder<TestDbContext>();
        //optionsBuilder.UseInMemoryDatabase();
        optionsBuilder.UseSqlServer("Server = (localdb)\\mssqllocaldb; Database = afmil_Test_next; Trusted_Connection = True; "
                );

        using (var context = new TestDbContext(optionsBuilder.Options))
        {
            var command = fixture.Create<PostRegisterStudentCommand>();
            var handler = new PostRegisterStudentCommandHandler(context);

            try
            {
                handler.Handle(command);
            }
            catch (DbUpdateException e)
            {
                var sb = new StringBuilder();
                sb.AppendLine($"DbUpdateException error details - {e?.InnerException?.InnerException?.Message}");

                foreach (var eve in e.Entries)
                {
                    sb.AppendLine($"Entity of type {eve.Entity.GetType().Name} in state {eve.State} could not be updated");
                }

                sb.ShouldBeNull();
            }

            var dbStudent = context.Students.FirstOrDefault();
            dbStudent.ShouldNotBeNull();
            dbStudent.User.FirstName.ShouldBe(command.FirstName);
        }

    }

I got the exception catch part from an EF 6 stackoverflow answer.

I've search everything I can think of to find a example of extracting entity validation issues (DbEntityValidationException from EF6) in EF Core but cannot find anything that seems to work.

As a suggestion from this EF Core github issue, I attempted to do some annotation validation like this. But this didn't find the issues that the db was having with my student object.

1
1
6/4/2018 2:13:50 PM

Popular Answer

Indeed EF7 lacks the validation that it is available in EF6. This seems to be a design choice as validation is assumed before models are sent to be saved (and also DB constraints might be used as a safety net).

This article shows how to manually perform validations before saving data. However, beware that this works for data annotation only. My slightly changed version is the following:

public void Validate()
{
    var entities = ChangeTracker.Entries()
        .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified)
        .Select(e => e.Entity)
        .ToList();

    foreach (var entity in entities)
    {
        var validationContext = new ValidationContext(entity);
        Validator.ValidateObject(entity, validationContext, validateAllProperties: true);
    }
}

My advice is to have a method to handle both type of exceptions (validation and database), something like the following:

try
{
    Validate();
    Context.SaveChanges();
}
catch(ValidationException exc)
{
    Logger.LogError(exc, $"{nameof(SaveChanges)} validation exception: {exc?.Message}");
    return false;
}
catch (DbUpdateException exc)
{
    Logger.LogError(exc, $"{nameof(SaveChanges)} db update error: {exc?.InnerException?.Message}");
    return false;
}
0
6/4/2018 2:20:16 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow