none
Having problems to use a "Buddy class" to avoid the Entity designer to overwrite DataAnnotations validation code RRS feed

  • Question

  • Hi all,

    My question is based on Scott's blog: http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx

    "One way you can apply additional attribute-based meta-data (like validation attributes) to a class that is auto-generated/maintained by a VS designer is to employ a technique we call “buddy classes”.  Basically you create a separate class that contains your validation attributes and meta-data, and then link it to the class generated by the designer by applying a “MetadataType” attribute to a partial class that is compiled with the tool-generated class.  For example, if we wanted to apply the validation rules we used earlier to a Person class maintained by a LINQ to SQL or ADO.NET EF designer we could update our validation code to instead live in a separate “Person_Validation” class that is linked to the “Person” class created by VS."

    Here is my code:


    namespace ContosoUniversity.Models
    {
        public abstract class Person
        {
            [Key]
            public int PersonID { get; set; }

            [Required(ErrorMessage = "Last name is required.")]
            [Display(Name = "Last Name")]
            [MaxLength(50)]
            public string LastName { get; set; }

            [Required(ErrorMessage = "First name is required.")]
            [Column("FirstName")]
            [Display(Name = "First Name")]
            [MaxLength(50)]
            public string FirstMidName { get; set; }
        }
    }


    namespace ContosoUniversity.Models
    {
        public class Student : Person
        {
            public DateTime? EnrollmentDate { get; set; }

            public virtual ICollection<Enrollment> Enrollments { get; set; }
        }
    }

    Here is where I think I am doing something wrong, I am trying to create a buddy class for the Student class:

    namespace ContosoUniversity.ValidationRules
    {
        [MetadataType(typeof(Student_Validation))]
        public partial class Student : Person
        {

        }

        public class Student_Validation
        {
            [Required(ErrorMessage = "Enrollment date is required.")]
            [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
            [Display(Name = "Enrollment Date")]
            public DateTime? EnrollmentDate { get; set; }
        }
    }

    I am getting the following error:

    The associated metadata type for type 'ContosoUniversity.ValidationRules.Student' contains the following unknown properties or fields: EnrollmentDate. Please make sure that the names of these members match the names of the properties on the main type.


    Line 18:         public IEnumerable<Student> GetStudents()
    Line 19:         {
    Line 20:             return context.Students.ToList(); <======================= Error
    Line 21:         }
    Line 22:

    Thank you

     


    Max
    Wednesday, October 26, 2011 10:30 PM

Answers

  • Alan,

    The error is gone but the validation is not working. I put a break point in the applciation and it never hits the Validation class:
    Here is what I have:

    File: Student.cs (this is the file which will get overwritten by the EF designer)
    
        public partial class Student : Person
        {
            public DateTime? EnrollmentDate { get; set; }
        }
    
    
    File: Student_Validation.cs (separate file in another folder)
    
        [MetadataType(typeof(Student_Validation))]
        partial class Student
        { }
    
        public class Student_Validation
        {
            [Required(ErrorMessage = "Enrollment date is required.")]
            [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
            [Display(Name = "Enrollment Date")]
            public DateTime? EnrollmentDate { get; set; }
        }
    
    

    Thank you


    Max
    • Marked as answer by Maximusdm Monday, November 7, 2011 8:07 PM
    Thursday, October 27, 2011 3:22 PM
  • Are you still separating the classes in different namespaces?  Try using the same namespace as Alan_chen's example shows.
    • Marked as answer by Maximusdm Monday, November 7, 2011 8:07 PM
    Friday, November 4, 2011 3:15 PM

All replies

  • Hi Max,

    Welcome!

    Firstly the Student Class should be "partial" class, the Buddy class doesn't need to inherit the person

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel.DataAnnotations;
    using System.Data.Entity;
    
    namespace ConsoleApplication3
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (var context= new MyContext())
                {
                    //context.Database.CreateIfNotExists();
                    var s = new Student {  PersonID=1, LastName="fa", FirstMidName="fa"};
                    context.Students.Add(s);
                    context.SaveChanges();
    
                }
            }
        }
        public abstract class Person
        {
            [Key]
            public int PersonID { get; set; }
    
            [Required(ErrorMessage = "Last name is required.")]
            [Display(Name = "Last Name")]
            [MaxLength(50)]
            public string LastName { get; set; }
    
            [Required(ErrorMessage = "First name is required.")]
            [Column("FirstName")]
            [Display(Name = "First Name")]
            [MaxLength(50)]
            public string FirstMidName { get; set; }
        }
        public partial class Student : Person
        {
            public DateTime? EnrollmentDate { get; set; }
        }
        [MetadataType(typeof(Student_Validation))]
        partial class Student
        { }
        public class Student_Validation
        {
            [Required(ErrorMessage = "Enrollment date is required.")]
            [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
            [Display(Name = "Enrollment Date")]
            public DateTime? EnrollmentDate { get; set; }
        }
        public class MyContext:DbContext
        {
            public DbSet<Student> Students { get; set; }
        } 
    
    }
    
    

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, October 27, 2011 6:52 AM
    Moderator
  • Alan,

    The error is gone but the validation is not working. I put a break point in the applciation and it never hits the Validation class:
    Here is what I have:

    File: Student.cs (this is the file which will get overwritten by the EF designer)
    
        public partial class Student : Person
        {
            public DateTime? EnrollmentDate { get; set; }
        }
    
    
    File: Student_Validation.cs (separate file in another folder)
    
        [MetadataType(typeof(Student_Validation))]
        partial class Student
        { }
    
        public class Student_Validation
        {
            [Required(ErrorMessage = "Enrollment date is required.")]
            [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
            [Display(Name = "Enrollment Date")]
            public DateTime? EnrollmentDate { get; set; }
        }
    
    

    Thank you


    Max
    • Marked as answer by Maximusdm Monday, November 7, 2011 8:07 PM
    Thursday, October 27, 2011 3:22 PM
  • Hi Max,

    Are use Code First in your MVC project, I test my code, it works but in console application, it should same with MVC, you can copy them and test it.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.


    Friday, October 28, 2011 6:26 AM
    Moderator
  • Hi,

    I am writing to check the status of the issue on your side.  Would you mind letting us know the result of the suggestions?

    If you need further assistance, please feel free to let me know.   I will be more than happy to be of assistance.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, November 4, 2011 6:26 AM
    Moderator
  • Are you still separating the classes in different namespaces?  Try using the same namespace as Alan_chen's example shows.
    • Marked as answer by Maximusdm Monday, November 7, 2011 8:07 PM
    Friday, November 4, 2011 3:15 PM
  • qaato,

    You got it! I had it in different namespaces! I wanted to separate the files in a different folder (ValidationRules) so that it would be easily found. I moved it inside the "Models" folder and changed the namespace, now it works.

    I did not realize it does not matter where you put the .cs files. As long as you type the correct name space it should work.

    Thanks!


    Max

    • Edited by Maximusdm Monday, November 7, 2011 8:07 PM
    Monday, November 7, 2011 7:49 PM
  • Thanks Alan!
    Max
    Monday, November 7, 2011 8:07 PM