Question

Debug EntityValidationErrors in Entity Framework 6 C#

csharpentity-frameworkentity-framework-4entity-framework-4.1

Question

I am seeding a database with Entity Framework Code First and context.SaveChanges() throws this exception:

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

Visual Studio shows that EntityValidationErrors contains eight entries, but I do not know how to inspect and identify the specific validation failures. I recently changed Status from an enum to an entity class and added two foreign keys from ApplicationPositionHistory to Status.

How can I view the detailed validation errors, and how can I correct the invalid seed data and relationship configuration?

Short Answer

You will learn how Entity Framework 6 validates entities before saving, how to inspect a DbEntityValidationException, and how to fix the invalid Status seed values causing this particular failure. You will also see how to configure two relationships from one entity to the same table.

Concept

Entity Framework 6 runs validation before it sends INSERT or UPDATE commands to the database. It uses validation attributes such as [Required], [StringLength], and other Data Annotations on your entity properties.

If one or more tracked entities fail validation, EF throws DbEntityValidationException. The short exception message is intentionally general. The useful details are in:

  • exception.EntityValidationErrors: the entities that failed validation.
  • Each entity's ValidationErrors: the invalid property, attempted value, and error message.

In this model, Status.status has this restriction:

[StringLength(20, MinimumLength = 3)]
public string status { get; set; }

Several seeded status names are longer than 20 characters, for example "Assigned to Technical Department". Those values violate the attribute, so EF stops SaveChanges() before saving any of the pending changes.

This validation is useful: it catches invalid data in application code rather than relying only on a database error after a save attempt.

Mental Model

Think of SaveChanges() as handing completed forms to a clerk.

Before accepting them, the clerk checks every field against the rules: required fields must be filled in, and text fields must fit their maximum length. If several forms have problems, the clerk says only, “Some forms are invalid.”

EntityValidationErrors is the clerk's detailed correction list. It tells you which form (entity), which field (property), and which rule failed.

Take Quiz

Syntax and Examples

Catch DbEntityValidationException around SaveChanges() and enumerate every validation error.

using System;
using System.Data.Entity.Validation;
using System.Linq;

try
{
    context.SaveChanges();
}
catch (DbEntityValidationException ex)
{
    foreach (var entityError in ex.EntityValidationErrors)
    {
        string entityName = entityError.Entry.Entity.GetType().Name;

        foreach (var validationError in entityError.ValidationErrors)
        {
            Console.WriteLine(
                "Entity: {0}, Property: {1}, Error: {2}",
                entityName,
                validationError.PropertyName,
                validationError.ErrorMessage);
        }
    }

    throw;
}

For a status longer than 20 characters, the output will identify the Status entity, the status property, and the message from its [StringLength] attribute.

To fix the model, choose a maximum length that matches the data you intend to store:

public class Status
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int StatusID { get; set; }

    [Required]
    [StringLength(50, MinimumLength = 3,
        ErrorMessage = "Status must be between 3 and 50 characters.")]
    public string status { get; set; }
}

Alternatively, shorten the seed values. The model rule and the actual data must agree.

Step by Step Execution

Consider this small example:

var status = new Status
{
    status = "Assigned to Technical Department"
};

context.Status.Add(status);
context.SaveChanges();

Execution flow:

  1. A new Status object is created with a 32-character value.
  2. context.Status.Add(status) marks it as Added; it does not insert it yet.
  3. SaveChanges() starts EF validation.
  4. EF reads [StringLength(20, MinimumLength = 3)] on Status.status.
  5. EF compares the value length with the maximum of 20.
  6. The value is too long, so EF adds a validation error for status.
  7. EF throws DbEntityValidationException and does not save the changes.

A diagnostic catch block turns the generic exception into a specific message you can fix.

Real World Use Cases

Entity validation appears in many EF6 applications:

  • Database seeding: Initial lookup data, test users, roles, and product categories must satisfy the same rules as normal application data.
  • Web forms and APIs: A request may omit a required field or submit text that exceeds a configured limit.
  • Import scripts: CSV or spreadsheet data often has unexpected long values, missing columns, or invalid formats.
  • Administrative tools: Internal dashboards should prevent invalid edits before data reaches the database.
  • Automated tests: Tests can verify that invalid entities are rejected and valid entities can be persisted.
Take Quiz

Real Codebase Usage

In production code, validation exceptions are usually logged with entity and property details rather than ignored.

A reusable helper can format validation failures:

using System.Collections.Generic;
using System.Data.Entity.Validation;
using System.Linq;

public static class ValidationErrorFormatter
{
    public static IEnumerable<string> Format(DbEntityValidationException ex)
    {
        return ex.EntityValidationErrors.SelectMany(entityError =>
        {
            string entityName = entityError.Entry.Entity.GetType().Name;

            return entityError.ValidationErrors.Select(error =>
                entityName + "." + error.PropertyName + ": " + error.ErrorMessage);
        });
    }
}

Typical use:

try
{
    context.SaveChanges();
}
catch (DbEntityValidationException ex)
{
    foreach (string message in ValidationErrorFormatter.Format(ex))
    {
        logger.Error(message);
    }

    throw;
}

For seed data, prefer navigation properties over guessed numeric foreign-key values. Instead of assuming the first status receives ID 1, connect the object directly:

var applicantPosition = new ApplicantPosition
{
    Applicant = luis,
    Position = netdeveloper,
    CurrentStatus = applied,
    appliedDate = DateTime.Today
};

EF understands this object relationship and assigns the foreign key when it saves the graph. This is safer than StatusID = 1, especially when seed order or existing data can change.

Common Mistakes

Looking only at the outer exception message

This message is not the actual reason for failure:

Validation failed for one or more entities.

Avoid it: inspect EntityValidationErrors in a catch (DbEntityValidationException ex) block.

Assuming the debugger's object count explains the failure

Seeing “8 objects” means multiple validation failures were collected. It does not tell you the failed properties. Enumerate ValidationErrors for each entity.

Defining a maximum length that does not fit valid data

This model allows only 20 characters:

[StringLength(20)]
public string status { get; set; }

But this seed value is longer:

new Status { status = "Approved by Technical Department" }

Avoid it: increase the limit, such as to 50, or use shorter business-approved names.

Assuming generated IDs during seeding

This is fragile:

StatusID = 1

An identity value is assigned by the database when saving. It may not be 1 in every environment. Avoid it: assign CurrentStatus = applied when you have the object available.

Leaving two relationships to the same entity ambiguous

ApplicationPositionHistory has oldStatus and newStatus, both of type Status. EF may need explicit configuration to distinguish the two foreign keys. Avoid it: configure each relationship with Fluent API and use clear navigation-property names.

Catching an exception and continuing as though the save succeeded

Do not silently swallow validation exceptions. Log their details, show appropriate user feedback when relevant, and correct the invalid data.

Comparisons

SituationBest approachWhy
Need details after EF validation failsCatch DbEntityValidationExceptionProvides entity, property, and error-message details.
Need to enforce simple property rulesData Annotations such as [Required] and [StringLength]Rules are close to the property and easy to read.
Need complex relationship mappingFluent API in OnModelCreatingBetter for multiple relationships, composite keys, and delete behavior.
Seed data refers to another new entityAssign a navigation propertyEF tracks the relationship without relying on hard-coded IDs.
Seed data refers to an already known database rowSet the foreign-key value, after confirming it existsUseful when the related entity is not being added in the same object graph.

Data Annotations and Fluent API can be used together. A common practice is to use annotations for basic validation and Fluent API for relationship configuration that would be unclear in attributes.

Take Quiz

Cheat Sheet

using System.Data.Entity.Validation;

try
{
    context.SaveChanges();
}
catch (DbEntityValidationException ex)
{
    foreach (var entityError in ex.EntityValidationErrors)
    {
        foreach (var error in entityError.ValidationErrors)
        {
            Console.WriteLine(error.PropertyName);
            Console.WriteLine(error.ErrorMessage);
        }
    }
    throw;
}
  • DbEntityValidationException is an EF6 validation exception.
  • EntityValidationErrors groups failures by entity instance.
  • ValidationErrors lists individual property failures.
  • [Required] rejects missing values.
  • [StringLength(maximum)] rejects strings longer than maximum.
  • Values in seed data must follow the same attributes as values submitted by users.
  • Prefer CurrentStatus = applied over a hard-coded StatusID = 1 when both objects are in the current unit of work.
  • Configure multiple foreign keys to the same table explicitly with Fluent API when conventions cannot determine the intended relationships.

FAQ

What is DbEntityValidationException in Entity Framework 6?

It is an exception EF6 throws when one or more tracked entities violate validation rules before EF writes changes to the database.

How do I see EntityValidationErrors in C#?

Catch DbEntityValidationException, then loop through ex.EntityValidationErrors and each item's ValidationErrors collection.

Why does SaveChanges() fail when I add valid-looking seed data?

Every seeded object is validated. A common cause is a string value that exceeds [StringLength], a missing required value, or an invalid relationship.

Which status values fail in this example?

The values containing phrases such as "Assigned to Technical Department" and "Approved by General Manager" exceed the declared 20-character maximum.

Should I use StatusID = 1 while seeding related entities?

Avoid it when you already have the related Status object in memory. Assign CurrentStatus = applied instead. It does not assume a particular database-generated ID.

How do I map old and new status foreign keys to the same Status table?

Use two separate foreign-key properties and configure two relationships in OnModelCreating, each pointing to its correct foreign key.

Does this exception mean the database transaction partially saved data?

Validation occurs before EF sends the normal save commands, so a validation failure prevents the invalid save operation from proceeding.

Take Quiz

Mini Project

Description

Create a small EF6 seed routine for application statuses. It demonstrates how a string-length rule affects seed data, how to display detailed validation failures, and how to link a new ApplicantPosition to a new Status through a navigation property.

Goal

Seed valid statuses and an applicant-position relationship, while printing useful details if validation fails.

Requirements

Use a Status entity with a maximum status length that accepts all seed values. Create at least two Status objects and add them to the context. Create an ApplicantPosition that refers to a Status through CurrentStatus. Wrap SaveChanges() in a DbEntityValidationException handler. Print the entity name, property name, and validation message for every failure.

Take Quiz

Keep learning

Related questions

View more