This is a migrated thread and some comments may be shown as answers.

Is there an equivalent to ToDataSourceResult for OpenAccess?

3 Answers 102 Views
LINQ (LINQ specific questions)
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Jelly Master
Top achievements
Rank 1
Jelly Master asked on 09 May 2014, 10:41 PM
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.





3 Answers, 1 is accepted

Sort by
0
Kristian Nikolov
Telerik team
answered on 14 May 2014, 08:32 AM
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.
 
0
Jelly Master
Top achievements
Rank 1
answered on 15 May 2014, 12:18 AM
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) .



 
0
Kristian Nikolov
Telerik team
answered on 16 May 2014, 01:56 PM
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.
 
Tags
LINQ (LINQ specific questions)
Asked by
Jelly Master
Top achievements
Rank 1
Answers by
Kristian Nikolov
Telerik team
Jelly Master
Top achievements
Rank 1
Share this question
or