none
problem to save data in multi layer EF application RRS feed

  • Question

  • Hi All.

    When I tried to save a new record I got such error message.

    I have such scenario in my multi layer application. In Data Layer (DL) I have method in EmployeeFactory class to save record

    private static int result;
    
    public static int SaveEmployee(EmployeeDT employee)
    {
        try
        {
            using (var context = new Model1())
            {
                var emp = new Employee
                {
                    EmployeeId = employee.EmployeeId,
                    Name = employee.Name,
                    Department = employee.Department,
                    IsActive = employee.IsActive,
                    CreatedDate = employee.CreatedDate,
                    CreatedBy = employee.CreatedBy
                };
    
                var result = context.Epmloyees.Add(emp);
                context.SaveChanges();
            }
            return result;
        catch Exception(ex)
        {
            throw new Exception("The data wasn't saved." + ex.ToString());
        }
    }


    In Business Layer (BL) the EmployeeAdapter class has method which pass data from BL to DL

    public int SaveEmployee(EmployeeDT employee)
    {
        return EmployeeFactory.SaveEmployee(employee);
    }


    And in UI Layer I have click Save button event method

    private void SaveEmployee_Click(object sender, RoutedEventArgs e)
    {
        var employee = new EmployeeDT();
    
        employee.EmployeeId = Guid.NewGuid();
        employee.Name = NameTextBox.Text;
        employee.Department = DepartmentTextBox.Text;
    employee.IsActive = IsActiveCheckBox.IsChecked.HasValue ? IsActiveCheckBox.IsChecked.Value : false; employee.CreatedDate = DateTime.Now; employee.CreatedBy = CreatedByTextBox.Text; var ea = new EmployeeAdapter(); ea.SaveEmployee(employee); }


    I will appreciate if someone explain and show how to fix problem and save record successfully.

    Thanks.






    • Edited by zleug Thursday, August 13, 2020 4:51 PM
    Thursday, August 13, 2020 4:36 PM

Answers

  • Suppose we have

    public class Employee
    {
        public int EmployeeId { get; set; }
        [Required]
        [StringLength(50)]
        public string LastName { get; set; }
        [Required]
        [StringLength(50)]
        public string FirstName { get; set; }
        [Required]
        public DateTime? HireDate { get; set; }
        [Required(ErrorMessage = "Please enter your {0} email address")]
        [DataType(DataType.EmailAddress)]
        [MaxLength(70)]
        [RegularExpression(@"[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}", 
            ErrorMessage = "Please enter correct {0} email")]
        public string PersonalEmail { get; set; }
    }

    And do this

    Employee employee = new Employee();
    var validationResult = ValidationHelper.ValidateEntity(employee);
    if (validationResult.HasError)
    {
        Console.WriteLine(validationResult.ErrorMessageList());
    }
    else
    {
        Console.WriteLine("Call save changes");
    }

    We get

    The Last Name field is required.
    The First Name field is required.
    The Hire Date field is required.
    Please enter your Personal Email email address

    If we do this

    Employee employee = new Employee()
    {
        LastName = "Payne",
        FirstName = "Karen",
        HireDate = DateTime.Now,
        PersonalEmail = "pk@gmail.com"
    };
    
    var validationResult = ValidationHelper.ValidateEntity(employee);
    if (validationResult.HasError)
    {
        Console.WriteLine(validationResult.ErrorMessageList());
    }
    else
    {
        Console.WriteLine("Call save changes");
    }

    We go to the else thus you perform the SaveChanges operation

    Now if I did this which violates the max length for FirstName

    FirstName = "Karen Karen Karen Karen Karen Karen Karen Karen Karen Karen"

    We get

    The field First Name must be a string with a maximum length of 50.



    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    • Marked as answer by zleug Thursday, August 20, 2020 12:06 PM
    Thursday, August 13, 2020 7:13 PM
    Moderator

All replies

  • Look at this library for performing validation.

    Given this class with CompanyName annotated for required and string length.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Runtime.CompilerServices;
    
    namespace North.Models
    {
        public partial class Customers : INotifyPropertyChanged
        {
            private int? _countryIdentifier;
    
            public Customers()
            {
                Orders = new HashSet<Orders>();
            }
    
            /// <summary>
            /// Id
            /// </summary>
            public int CustomerIdentifier { get; set; }
            /// <summary>
            /// Company
            /// </summary>
            [Required]
            [StringLength(40, ErrorMessage = "Description Max Length is 40")]
            public string CompanyName { get; set; }
            /// <summary>
            /// ContactId
            /// </summary>
            public int? ContactId { get; set; }
            /// <summary>
            /// Street
            /// </summary>
            public string Street { get; set; }
            /// <summary>
            /// City
            /// </summary>
            public string City { get; set; }
            /// <summary>
            /// Region
            /// </summary>
            public string Region { get; set; }
            /// <summary>
            /// Postal Code
            /// </summary>
            public string PostalCode { get; set; }
    
            /// <summary>
            /// CountryIdentifier
            /// </summary>
            public int? CountryIdentifier
            {
                get => _countryIdentifier;
                set
                {
                    _countryIdentifier = value;
                    OnPropertyChanged();
                }
            }
    
            /// <summary>
            /// Phone
            /// </summary>
            public string Phone { get; set; }
            /// <summary>
            /// Fax
            /// </summary>
            public string Fax { get; set; }
            /// <summary>
            /// ContactTypeIdentifier
            /// </summary>
            public int? ContactTypeIdentifier { get; set; }
            /// <summary>
            /// Modified Date
            /// </summary>
            public DateTime? ModifiedDate { get; set; }
    
            public virtual Contacts Contact { get; set; }
            public virtual ContactType ContactTypeIdentifierNavigation { get; set; }
            public virtual Countries CountryIdentifierNavigation { get; set; }
            public virtual ICollection<Orders> Orders { get; set; }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
        }
    }

    If I create a new Customer without supplying the company name or the company name is too long the following catches it before doing a SaveChanges.

    var customer = new Customers();
    var validationResult = ValidationHelper.ValidateEntity(customer);
    if (validationResult.HasError)
    {
        Console.WriteLine(validationResult.ErrorMessageList());
    }
    

    We get

    Validation issues
    The Company Name field is required .


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Thursday, August 13, 2020 4:56 PM
    Moderator
  • Hi Karen. Thanks for reply.

    My EmployeeDT class has same properties like entity Employee table. 

    public class EmployeeDT
    {
        public int Id { get; set; }
        public Guid EmployeeId { get; set; }
        public string Name { get; set; }
        public string Department { get; set; }
        public bool IsActive { get; set; }
        public DateTime CreatedDate { get; set; }
        public string CreatedBy { get; set; }
        public DateTime UpdatedDate { get; set; }
        public string UpdatedBy { get; set; }
    }


    If I understood your correctly when I try to save a record I must specify all properties in save operation. And if to add two Update properties a record will saved. Is that correct?

    Thanks.



    • Edited by zleug Thursday, August 13, 2020 5:56 PM
    Thursday, August 13, 2020 5:27 PM
  • No, what Karen has shown you is a way to get what the validation errors were. 

    Looking for new opportunities

    For every expert, there is an equal and opposite expert. - Becker's Law


    My blog


    My TechNet articles

    Thursday, August 13, 2020 6:15 PM
    Moderator
  • Most likely, EF is trying to save data in one datatable column that's being truncated.

    If you want to see the EF validation error, then you have to place code in the solution to expose it.

    https://blogs.infosupport.com/improving-dbentityvalidationexception/

    I would also recommend that you use global exception handling not having a try/catch in any code in any of the layers and let the GEH catch the error in the presentation layer where you can log it or expose it in a messagebox. If you log the exception to a logging framework like Log4Net, then you should include the error message, the stack trace and the inner.execption message if it is not null.

    You should be able to detect that EF validation exception in the GEH and expose the validation error as being shown to you in the link, and again.  you should not use a try/catch for the code in the GEH to know that it's an EF validation error.

    https://www.codeproject.com/Articles/43182/Centralised-Exception-Handling-in-C-Windows-Applic

    https://stackify.com/csharp-catch-all-exceptions/

    The program.cs in the presentation layer,  which is the root project, for the Windows  multilayer example solution out on Github implements the GEH. If you look at the code of the solution, you will see that there is not a try/catch in any code in any layer, and all expectations are caught by the GEH in the presentation layer.

    https://github.com/darnold924/PubComanyWinCore

    Thursday, August 13, 2020 7:00 PM
  • Suppose we have

    public class Employee
    {
        public int EmployeeId { get; set; }
        [Required]
        [StringLength(50)]
        public string LastName { get; set; }
        [Required]
        [StringLength(50)]
        public string FirstName { get; set; }
        [Required]
        public DateTime? HireDate { get; set; }
        [Required(ErrorMessage = "Please enter your {0} email address")]
        [DataType(DataType.EmailAddress)]
        [MaxLength(70)]
        [RegularExpression(@"[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}", 
            ErrorMessage = "Please enter correct {0} email")]
        public string PersonalEmail { get; set; }
    }

    And do this

    Employee employee = new Employee();
    var validationResult = ValidationHelper.ValidateEntity(employee);
    if (validationResult.HasError)
    {
        Console.WriteLine(validationResult.ErrorMessageList());
    }
    else
    {
        Console.WriteLine("Call save changes");
    }

    We get

    The Last Name field is required.
    The First Name field is required.
    The Hire Date field is required.
    Please enter your Personal Email email address

    If we do this

    Employee employee = new Employee()
    {
        LastName = "Payne",
        FirstName = "Karen",
        HireDate = DateTime.Now,
        PersonalEmail = "pk@gmail.com"
    };
    
    var validationResult = ValidationHelper.ValidateEntity(employee);
    if (validationResult.HasError)
    {
        Console.WriteLine(validationResult.ErrorMessageList());
    }
    else
    {
        Console.WriteLine("Call save changes");
    }

    We go to the else thus you perform the SaveChanges operation

    Now if I did this which violates the max length for FirstName

    FirstName = "Karen Karen Karen Karen Karen Karen Karen Karen Karen Karen"

    We get

    The field First Name must be a string with a maximum length of 50.



    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    • Marked as answer by zleug Thursday, August 20, 2020 12:06 PM
    Thursday, August 13, 2020 7:13 PM
    Moderator
  • EmployeeDT? What does DT stand for datatable? Yikes!

    It's a POCO or a DTO with DTO being sent through the layers. There is no datatable in EF if that's what DT stands for. 

    https://www.entityframeworktutorial.net/Types-of-Entities.aspx

    Thursday, August 13, 2020 7:14 PM
  • I am also going to recommend to you that you don't confuse a domain object with a persistence object, becuase I see you are starting to go in that direction.

    An object with data annotation is trying to implement behavior and is a form of business logic a domain object. A domain object and a persistence object used by a persistence framework are objects with two different purposes. 

    https://blog.sapiensworks.com/post/2012/04/07/Just-Stop-It!-The-Domain-Model-Is-Not-The-Persistence-Model.aspx

      
    Thursday, August 13, 2020 7:28 PM