Is there an equivalent to ToDataSourceResult for OpenAccess?

4 posts, 0 answers
  1. Jelly Master
    Jelly Master avatar
    39 posts
    Member since:
    Oct 2010

    Posted 09 May 2014 Link to this post

    Let me see if I can explain this:
    First I have a simple EntitiesModel created via the designer which currently have one table for now but will include more later (This unfortunately is on a database this has had some abuse of the years and relationships are "loosely" enforced, but I digress)

    Now I have an MVC application that is using Data Access via a service layer which both projects share a viewmodel project.

    So if I have for Example

    1 project with Open Access Entity (Accessed only by the service layer)  
    1 Project with View Models (Accessed by service layer and Application)
    1 Project with Service Layer (Accessed by Application)
    1 Project MVC Application


    So for example I may have a class like this in my Open Access Entity Class:
    01.public partial class Student
    02.    {
    03.        private Guid _iD;
    04.        public virtual Guid ID
    05.        {
    06.            get
    07.            {
    08.                return this._iD;
    09.            }
    10.            set
    11.            {
    12.                this._iD = value;
    13.            }
    14.        }
    15.         
    16.        private Guid _schoolsID;
    17.        public virtual Guid SchoolsID
    18.        {
    19.            get
    20.            {
    21.                return this._schoolsID;
    22.            }
    23.            set
    24.            {
    25.                this._schoolsID = value;
    26.            }
    27.        }
    28.         
    29.        private Guid _gendersID;
    30.        public virtual Guid GendersID
    31.        {
    32.            get
    33.            {
    34.                return this._gendersID;
    35.            }
    36.            set
    37.            {
    38.                this._gendersID = value;
    39.            }
    40.        }
    41.         
    42.        private string _firstName;
    43.        public virtual string FirstName
    44.        {
    45.            get
    46.            {
    47.                return this._firstName;
    48.            }
    49.            set
    50.            {
    51.                this._firstName = value;
    52.            }
    53.        }
    54.         
    55.        private string _lastName;
    56.        public virtual string LastName
    57.        {
    58.            get
    59.            {
    60.                return this._lastName;
    61.            }
    62.            set
    63.            {
    64.                this._lastName = value;
    65.            }
    66.        }
    67.         
    68.}

    Then have a view on this entity in the model project like this:

    01.    public class StudentModel
    02.    {
    03.         
    04.        public Guid ID { get; set; }
    05. 
    06.        [Required]
    07.        [Display(Name = "Gender")]
    08.        public string GenderID { get; set; }
    09. 
    10.        [Required]
    11.        [Display(Name = "First Name")]
    12.        public string FirstName { get; set; }
    13. 
    14.        [Required]
    15.        [Display(Name = "Last Name")]
    16.        public string LastName { get; set; }
    17. 
    18.        [Required]
    19.        [Display(Name = "Date of Birth")]
    20.        public DateTime? DateOfBirth { get; set; }
    21. 
    22.        [Required(AllowEmptyStrings = true)]
    23.        [Display(Name = "UPN")]
    24.        public string UpnNumber { get; set; }
    25. 
    26.        [Required(AllowEmptyStrings = true)]
    27.        [Display(Name = "Adno")]
    28.        public string Adno { get; set; }
    29. 
    30.        [Required]
    31.        [Display(Name = "Left School")]
    32.        public bool HasLeft { get; set; }
    33. 
    34.}

    Which as you can see is pretty much a copy of the open access model.

    So if I was using this model in a Kendo Grid and had filtering, paging, sorting etc. being used I want to be able to pass these options back through the chain to the service layer and then some how translate the various options that have been created via the DataSourceRequest object associated with the grid and perform the filtering, sorting, grouping etc on the server before bringing the results back so that I can then cast them from the Open Access entity to the view model entity.

    so for example I have something like this in the service layer:
    01.List<StudentViewModel> model = OaContext.Students.OrderBy("my sorting options").Where("my group of filters").Select(s => new StudentViewModel()
    02.                {
    03.                    ID = s.ID,
    04.                    FirstName = s.FirstName,
    05.                    LastName = s.LastName,
    06.                    UPN = s.UPN,
    07.                    DateOfBirth = s.DateOfBirth,
    08.                    YearGroup = s.Adno
    09.                }
    10.               ).ToList();

    I need some mechanism to be able to try and cast/convert/reflect the viewmodel back to the open access entity so that I can apply the filters, sorting etc to the right properties in the sql query.

    Ideally I would like a generic solution in which I can just pass in my viewmodel T and output it to OpenAccess Entity U so that the dynamic linq created can apply the filters correctly.

    Hopefully this explains what it is I am after.

    What I want to avoid is having to repeat a lot of code for something that I know I will do a lot for this project and future projects. It also means if I change the model then I don't have to change the business logic too much to account for a filter being added/removed.

    Thanks in advance for any assistance with this.





  2. Kristian Nikolov
    Admin
    Kristian Nikolov avatar
    206 posts

    Posted 14 May 2014 Link to this post

    Hi David,

    Thank you for contacting us.

    If I am understanding your scenario correctly, you need to convert from a ViewModel back to the respective Entity type where the ViewModel type consists of a subset of the properties of the Entity type. As per your example you would need to convert objects of StudentViewModel back to Student.

    Should this indeed be the case, you could implement a generic method which does this using reflection. The following code snippet is an example of such method:
    private static List<TEntity> ToPersistentEntityType<TViewModel, TEntity>(IEnumerable<TViewModel> viewModels)
    {
        List<TEntity> result = new List<TEntity>();
     
        foreach (TViewModel viewModel in viewModels)
        {
            //instantiate an entity object
            TEntity entity = Activator.CreateInstance<TEntity>();
     
            //enumerate through the properties of the ViewModel
            //and populate the respective properties in the Entity object
            foreach (var property in typeof(TViewModel).GetProperties())
            {
                string propName = property.Name;
                object propVal = property.GetValue(viewModel);
                PropertyInfo propertyToSet = entity.GetType().GetProperty(propName);
                propertyToSet.SetValue(entity, propVal);
            }
            result.Add(entity);
        }
     
        return result;
    }

    There are two requirements for this approach to work - the TViewModel type should consist of a subset of the properties of the TEntity type. Additionally the common properties between the TViewModel and TEntity types should have the same names and types.

    I hope this helps. In case you have additional questions or need help, do not hesitate to get back to us using our forums or the Ticket System.

    Regards,
    Kristian Nikolov
    Telerik
     
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
     
  3. DevCraft banner
  4. Jelly Master
    Jelly Master avatar
    39 posts
    Member since:
    Oct 2010

    Posted 14 May 2014 in reply to Kristian Nikolov Link to this post

    Thanks for code I have modified it to make it a bit easier to manage from my point of view.

    Due to the view model containing properties that may not exist in the Open Access model ie computed Get fields ie DateTimeToStringFormat etc.

    In addition as you said the code provided will only map the view model property to the Open Access model property if they had the right name.

    So I have created a Data Annotation that will allow me to provide the database name as an Attribute using this code:


    01.public class ModelBindingAnnotationAttribute : Attribute
    02.  {
    03. 
    04.      public string DBName { get; set; }
    05. 
    06.      public ModelBindingAnnotationAttribute(string databaseColumnName = "")
    07.      {
    08.          DBName = databaseColumnName;
    09.      }
    10. 
    11.  }


    Then modifying your code I have done this:
    01.public TEntity ConvertViewModelToModel<TViewModel, TEntity>(TViewModel entity)
    02.        {
    03.            //Create the returning type
    04.            TEntity model = Activator.CreateInstance<TEntity>();
    05. 
    06.            //Initialize the model binding property name and value variables
    07.            string propertyName = string.Empty;
    08.            object propertyValue = null;
    09. 
    10.            //Cycle through the propery enumerations on the passed in model; 
    11.            foreach (var property in typeof(TViewModel).GetProperties())
    12.            {
    13. 
    14. 
    15.                //find out if we have the ViewModel to OpenAccess Object Mapping
    16.                var propertyAttribute = property.GetCustomAttribute(typeof(ModelBindingAnnotationAttribute));
    17. 
    18. 
    19.                //Check if we have a valid attribute item.
    20.                if (propertyAttribute != null)
    21.                {
    22.                    //We do but check we can cast it to the correct item
    23.                    var modelAttribute = propertyAttribute as ModelBindingAnnotationAttribute;
    24.                    if (modelAttribute != null)
    25.                    {
    26.                        //If in debug mode write a line to indicate the database property name found against the view model property selected
    27.#if DEBUG
    28.                        Debug.WriteLine(string.Format("Found Model Binding Annontation {0} on property {1}", modelAttribute.DBName, property.Name));
    29.#endif
    30.                        propertyName = modelAttribute.DBName;
    31.                    }
    32.                    else
    33.                    {
    34.                        //No conversion found use original property name
    35.                        propertyName = property.Name;
    36.                    }
    37. 
    38.                }
    39.                else
    40.                {
    41.                    //No conversion found use original property name
    42.                    propertyName = property.Name;
    43.                }
    44. 
    45. 
    46.                //Get the value of the property found within the view model;
    47.                propertyValue = property.GetValue(entity);
    48. 
    49.                //Create the property object that we will be setting.
    50.                PropertyInfo propertyToSet = model.GetType().GetProperty(propertyName);
    51. 
    52.                //Check we have a property found in the model
    53.                if (propertyToSet != null)
    54.                {
    55.                    //Valid object in the returning model and set the value;
    56.                    propertyToSet.SetValue(model, propertyValue);
    57.                }
    58.                else
    59.                {
    60.                    //If in debug mode then write down the propery we ignored.
    61.                    #if DEBUG
    62.                    Debug.WriteLine(string.Format("Property {0} was ignored due to not being part of return model", propertyName));
    63.                    #endif
    64.                }
    65.            }
    66. 
    67. 
    68. 
    69.            return model;
    70. 
    71.        }


    This way I now can get the conversion routine to ignore those properties it doesn't find and also means I don't have to use "ugly public property names"

    Have provided this code for others to see and use if they need in the future. 

    Now to work on the next bit.

    Again thanks for the original code base (outstanding support as usual) .



     
  5. Kristian Nikolov
    Admin
    Kristian Nikolov avatar
    206 posts

    Posted 16 May 2014 Link to this post

    Hello David,

    We are glad things are working on your side and thank you for providing this code for other users that might be interested.

    Do contact us again in case you have questions or need help.

    Regards,
    Kristian Nikolov
    Telerik
     
    OpenAccess ORM is now Telerik Data Access. For more information on the new names, please, check out the Telerik Product Map.
     
Back to Top