user9975473
user9975473

Reputation:

System.Data.Entity.Validation.DbEntityValidationException

I have a project that uses Entity Framework. While calling SaveChanges on my DbEntityValidationException, I get the following exception:

System.Data.Entity.Validation.DbEntityValidationException: 'Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.'

This is all fine and dandy, but I don't want to attach a debugger every time this exception occurs. More over, in production environments I cannot easily attach a debugger so I have to go to great lengths to reproduce these errors.

How can I see the details hidden within the DbEntityValidationException?

DbEntityValidationException

private void btnCreateLetter_Click(object sender, EventArgs e)
{

    using (TransactionScope TS = new TransactionScope())
    {
        try
        {
            Letter TblLetter = new Letter();
            TblLetter.Subject = txtSubject.Text.Trim();
            TblLetter.Abstract = txtAbstract.Text.Trim();
            TblLetter.Body = ckeCKEditor.TextEditor.Text.Trim();
            {
                var LastLetterID = (from Letter in Database.Letters orderby Letter.LetterID descending select Letter).First();
                TblLetter.LetterNO = PublicVariable.TodayDate.Substring(0, 4).Substring(2, 2) + PublicVariable.gDetermineJobLevel + "/" + (LastLetterID.LetterID + 1);
            }
            TblLetter.CreateDate = lblCreateDate.Text;
            TblLetter.UserID = PublicVariable.gUserID;
            if (rdbClassification.Checked == true)
            {
                TblLetter.SecurityType = 1;
            }
            else if (rdbConfidential.Checked == true)
            {
                TblLetter.SecurityType = 2;
            }
            else if (rdbSeries.Checked == true)
            {
                TblLetter.SecurityType = 3;
            }
            if (rdbActionType.Checked == true)
            {
                TblLetter.UrgencyType = 1;
            }
            else if (rdbInstantaneous.Checked == true)
            {
                TblLetter.UrgencyType = 2;
            }
            else if (rdbAnnie.Checked == true)
            {
                TblLetter.UrgencyType = 3;
            }
            TblLetter.ArchivesType = 1;
            if (rdbFollowHas.Checked == true)
            {
                TblLetter.FollowType = 1;
            }
            else if (rdbFollowHasnoot.Checked == true)
            {
                TblLetter.FollowType = 2;
            }
            if (rdbAttachmentHas.Checked == true)
            {
                TblLetter.AttachmentType = 1;
            }
            else if (rdbAttachmentHasnot.Checked == true)
            {
                TblLetter.AttachmentType = 2;
            }
            TblLetter.ReadType = 1;
            TblLetter.LetterType = 1;
            TblLetter.DraftType = 1;

            if (rdbResponseDeadlineHas.Checked == true)
            {
                TblLetter.AnswerType = 1;
                TblLetter.AnswerReadLine = String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(pdpSetResponseDeadline.Value.Year.ToString() +
                    "/" + pdpSetResponseDeadline.Value.Month.ToString() + "/" + pdpSetResponseDeadline.Value.Day.ToString()));
            }
            else if (rdbResponseDeadlineHasnot.Checked == true)
            {
                TblLetter.AnswerType = 2;
            }
            Database.Letters.Add(TblLetter);
            Database.SaveChanges();
            if (rdbAttachmentHas.Checked == true)
            {
                if (lblPath.Text != "")
                {
                    FileStream ObjectFileStream = new FileStream(lblPath.Text, FileMode.Open, FileAccess.Read);
                    int Lenght = Convert.ToInt32(ObjectFileStream.Length);
                    byte[] ObjectData;
                    ObjectData = new byte[Lenght];
                    string[] strPath = lblPath.Text.Split(Convert.ToChar(@"\"));
                    ObjectFileStream.Read(ObjectData, 0, Lenght);
                    ObjectFileStream.Close();

                    AttachFile TableAttachFile = new AttachFile();
                    TableAttachFile.FileSize = Lenght / 1024;
                    TableAttachFile.FileName = strPath[strPath.Length - 1];
                    TableAttachFile.FileData = ObjectData;
                    TableAttachFile.LetterID = TblLetter.LetterID;
                    Database.AttachFiles.Add(TableAttachFile);
                    Database.SaveChanges();
                }
            }
            TS.Complete();
            MessageBox.Show("saved", "ok", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch (InvalidCastException ex)
        {
            MessageBox.Show(ex.ToString());
            MessageBoxIcon.Error);
            return;
        }
    }
}

Upvotes: 3

Views: 2817

Answers (2)

Kira Hao
Kira Hao

Reputation: 1137

As mention, you need to check on your EntityValidationError when it throws the exception.

You should fix that validation error, instead of asking bypass this exception.

Normally these errors are table allow length, data type, column does not allow null and etc. There will be exact fiend name mention in your exception too.

Upvotes: 0

Craig.Feied
Craig.Feied

Reputation: 2840

You have to get the validation errors from the db.SaveChanges() method of the DatabaseContext object -- you can't get them where you are.

You can either modify the SaveChanges() method of your database context and wrap it in a try-catch block, or (since the class is partial) you can extend the partial class within your application and just override the SaveChanges() method.

There is a nice blog post about this called Easy way to improve DbEntityValidationException of Entity Framework here.

The essence of it is something like this:

public partial class NorthwindEntities
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            // Retrieve the error messages as a list of strings.
            var errorMessages = ex.EntityValidationErrors
                    .SelectMany(x => x.ValidationErrors)
                    .Select(x => x.ErrorMessage);

            // Join the list to a single string.
            var fullErrorMessage = string.Join("; ", errorMessages);

            // Combine the original exception message with the new one.
            var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);

            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

The blogger explains:

That’s it! The rest of your code will automatically use the overridden SaveChanges so you don’t have to change anything else. From now on, your exceptions will look like this:

System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. The validation errors are: The field PhoneNumber must be a string or array type with a maximum length of '12'; The LastName field is required.

The DbEntityValidationException also contains the entities that caused the validation errors. So if you require even more information, you can change the above code to output information about these entities.

Upvotes: 2

Related Questions