53
Reflection in C# Case studies in metaprogramming torsdag 6 mars 14

Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Reflection in C#Case studies in metaprogramming

torsdag 6 mars 14

Page 2: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

GenericDAO

torsdag 6 mars 14

Page 3: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

ORM for legacy DB

• DB with T-SQL Stored Procedures (SP)

• Apps written in C#, VB .Net and VB6

• Domain classes require mapping classes

• Different SP:s return different sets of data for the same domain objects

• Related data..

torsdag 6 mars 14

Page 4: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Domain class - 1 DAO

Service Layer

Data Access Layer

Domain Model

Database

Interface Layer UI Model

torsdag 6 mars 14

Page 5: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Domain class - 1 DAO

Service Layer

Data Access Layer

Domain Model

Database

Interface Layer UI Model

torsdag 6 mars 14

Page 6: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Domain class - 1 DAO

firstNamelastNameemploymentsaddress

PersongetAll()get(int id)getByUserName(string userName)...

PersonDAO

DB

SQL query

tabulated result sets

login(string user)logout(string user)

LoginService

Service Layer

Data Access Layer

Domain Model

Database

Interface Layer UI Model

torsdag 6 mars 14

Page 7: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Domain class - 1 DAO

firstNamelastNameemploymentsaddress

PersongetAll()get(int id)getByUserName(string userName)...

PersonDAO

DB

SQL query

tabulated result sets

login(string user)logout(string user)

LoginService

Service Layer

Data Access Layer

Domain Model

Database

Interface Layer UI Model

gradedate

Grade getAll()get(int id)getBy(string studentName, string courseName)...

GradeDAO

codecreditsteacherstudents

CoursegetAll()get(int id)getByName(string courseName)...

CourseDAO

torsdag 6 mars 14

Page 8: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Related data

people.SelectMany(p => p.Employments)

Do we know if employments have been fetched?

What if we only want to make one DB call? (Select 1+N Problem)

var people = new PersonDAO().GetAll()

firstName: "Ola"lastName: "Leifler"employmentsaddress

Person

nullnull

firstName: "Berit"lastName: "Larsson"employmentsaddress

Person

nullnull

torsdag 6 mars 14

Page 9: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Legacy supportfirstNamelastNameemploymentsaddress

PersongetAll()get(int id)getByEmployment(int id)getWithAddress(int id)

PersonDAO

DB

fName: "Ola"lName: "Leifler"

fName: "Berit"lName: "Jansson"

"getAll"

getAll()get(int id)getByEmployment(int id)getWithAddress(int id)

PersonDAO

DB

"getWithAddress"

firstName: "Ola"llastName: "Leifler"streetaddress: "Storgatan 1"city: "Linköping"

torsdag 6 mars 14

Page 10: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Legacy supportfirstNamelastNameemploymentsaddress

PersongetAll()get(int id)getByEmployment(int id)getWithAddress(int id)

PersonDAO

DB

fName: "Ola"lName: "Leifler"

fName: "Berit"lName: "Jansson"

"getAll"

getAll()get(int id)getByEmployment(int id)getWithAddress(int id)

PersonDAO

DB

"getWithAddress"

firstName: "Ola"llastName: "Leifler"streetaddress: "Storgatan 1"city: "Linköping"

torsdag 6 mars 14

Page 11: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Legacy supportfirstNamelastNameemploymentsaddress

PersongetAll()get(int id)getByEmployment(int id)getWithAddress(int id)

PersonDAO

DB

fName: "Ola"lName: "Leifler"

fName: "Berit"lName: "Jansson"

"getAll"

getAll()get(int id)getByEmployment(int id)getWithAddress(int id)

PersonDAO

DB

"getWithAddress"

firstName: "Ola"llastName: "Leifler"streetaddress: "Storgatan 1"city: "Linköping"

streetaddresscity

Address

torsdag 6 mars 14

Page 12: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Solution

• 1 Generic Data Access Object class

• Dynamic name resolution of Stored Procedures

• Generated proxy classes for lazy loading

• Markup and configuration to configure loading related objects, and mapping between data fields and class properties

torsdag 6 mars 14

Page 13: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Generic DAO            var people = GenericDAO<Domain.Person>.Get("GetPeopleByRole", new { RoleId = 3 });            people.Should().NotBeEmpty();

torsdag 6 mars 14

Page 14: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Generic DAO        private static ICollection<T> GetEntities(string procedureName,object parameterObject,                                                  int limit) {            int recordsRead=0;            var config=GetConfig(procedureName);            IList<T> entities=new ConcurrentList<T>();            try {                using(DbCommand command=BuildCommand(procedureName,parameterObject)) {                    using(IDataReader reader=command.ExecuteReader()) {                        var fieldNames=reader.Names();                        config.Init(command,fieldNames);                        var allFieldsUsed=config.GetAllFieldsUsedBy(reader);                        if((config.Policy&                             GenericDAO.ExceptionPolicy.AbortOnFieldsUnused)!=0&&                            !fieldNames.IsSubSetOf(allFieldsUsed)) {                            // Abort if some SQL result fields are unused                            throw new FieldsUnusedFromQueryException(fieldNames.Except(allFieldsUsed));                        }                        // Add a mapping from the SP to the properties it can set on the current object                        while(reader.Read()&&++recordsRead<limit) {                            entities.Add(config.InjectFrom(reader));                        }                    }                }                entities=config.Process(entities);            } finally {                DBAccess.CloseConnection();            }            return entities;        }

            var people = GenericDAO<Domain.Person>.Get("GetPeopleByRole", new { RoleId = 3 });            people.Should().NotBeEmpty();

torsdag 6 mars 14

Page 15: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Generic DAO        private static ICollection<T> GetEntities(string procedureName,object parameterObject,                                                  int limit) {            int recordsRead=0;            var config=GetConfig(procedureName);            IList<T> entities=new ConcurrentList<T>();            try {                using(DbCommand command=BuildCommand(procedureName,parameterObject)) {                    using(IDataReader reader=command.ExecuteReader()) {                        var fieldNames=reader.Names();                        config.Init(command,fieldNames);                        var allFieldsUsed=config.GetAllFieldsUsedBy(reader);                        if((config.Policy&                             GenericDAO.ExceptionPolicy.AbortOnFieldsUnused)!=0&&                            !fieldNames.IsSubSetOf(allFieldsUsed)) {                            // Abort if some SQL result fields are unused                            throw new FieldsUnusedFromQueryException(fieldNames.Except(allFieldsUsed));                        }                        // Add a mapping from the SP to the properties it can set on the current object                        while(reader.Read()&&++recordsRead<limit) {                            entities.Add(config.InjectFrom(reader));                        }                    }                }                entities=config.Process(entities);            } finally {                DBAccess.CloseConnection();            }            return entities;        }

            var people = GenericDAO<Domain.Person>.Get("GetPeopleByRole", new { RoleId = 3 });            people.Should().NotBeEmpty();

torsdag 6 mars 14

Page 16: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

1 Generic DAO        private static ICollection<T> GetEntities(string procedureName,object parameterObject,                                                  int limit) {            int recordsRead=0;            var config=GetConfig(procedureName);            IList<T> entities=new ConcurrentList<T>();            try {                using(DbCommand command=BuildCommand(procedureName,parameterObject)) {                    using(IDataReader reader=command.ExecuteReader()) {                        var fieldNames=reader.Names();                        config.Init(command,fieldNames);                        var allFieldsUsed=config.GetAllFieldsUsedBy(reader);                        if((config.Policy&                             GenericDAO.ExceptionPolicy.AbortOnFieldsUnused)!=0&&                            !fieldNames.IsSubSetOf(allFieldsUsed)) {                            // Abort if some SQL result fields are unused                            throw new FieldsUnusedFromQueryException(fieldNames.Except(allFieldsUsed));                        }                        // Add a mapping from the SP to the properties it can set on the current object                        while(reader.Read()&&++recordsRead<limit) {                            entities.Add(config.InjectFrom(reader));                        }                    }                }                entities=config.Process(entities);            } finally {                DBAccess.CloseConnection();            }            return entities;        }

            var people = GenericDAO<Domain.Person>.Get("GetPeopleByRole", new { RoleId = 3 });            people.Should().NotBeEmpty();

torsdag 6 mars 14

Page 17: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Dynamic name resolution

torsdag 6 mars 14

Page 18: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Dynamic name resolution

GetAll()GetPeopleByRole()

x 500

torsdag 6 mars 14

Page 19: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Dynamic name resolution

GetAll()GetPeopleByRole()

x 500

”GetAll””GetPeopleByRole”

x 500

torsdag 6 mars 14

Page 20: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Dynamic name resolution

GetAll()GetPeopleByRole()

x 500

”GetAll””GetPeopleByRole”

x 500

torsdag 6 mars 14

Page 21: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Dynamic name resolution

using System;using System.Collections.Generic;using System.Linq;using System.Dynamic;using Configuration;using Extensions;

namespace Core {    public class Dispatcher<T>:DynamicObject where T:class, new() {[ ... ]    public override bool TryInvokeMember(InvokeMemberBinder binder,                                             object[] args,                                             out object result) {            string procedureName=binder.Name;            object paramObj=GetParameterObject(binder,args);            string storedProcedureName=GenericDAO<T>.StoredProcedureFullName(procedureName);            if(procedureName.StartsWith("Get")) {                result=GetResult(paramObj,storedProcedureName);            } [ ... ] }}

GetAll()GetPeopleByRole()

x 500

”GetAll””GetPeopleByRole”

x 500

torsdag 6 mars 14

Page 22: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Dynamic name resolution

using System;using System.Collections.Generic;using System.Linq;using System.Dynamic;using Configuration;using Extensions;

namespace Core {    public class Dispatcher<T>:DynamicObject where T:class, new() {[ ... ]    public override bool TryInvokeMember(InvokeMemberBinder binder,                                             object[] args,                                             out object result) {            string procedureName=binder.Name;            object paramObj=GetParameterObject(binder,args);            string storedProcedureName=GenericDAO<T>.StoredProcedureFullName(procedureName);            if(procedureName.StartsWith("Get")) {                result=GetResult(paramObj,storedProcedureName);            } [ ... ] }}

GetAll()GetPeopleByRole()

x 500

”GetAll””GetPeopleByRole”

x 500

torsdag 6 mars 14

Page 23: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

            dynamic dao = GenericDAO<Domain.Person>.Dispatch();            IEnumerable<Domain.Person> people = dao.GetPeopleByRole(RoleId: 3);            people.Should().NotBeEmpty();

Dynamic name resolution

using System;using System.Collections.Generic;using System.Linq;using System.Dynamic;using Configuration;using Extensions;

namespace Core {    public class Dispatcher<T>:DynamicObject where T:class, new() {[ ... ]    public override bool TryInvokeMember(InvokeMemberBinder binder,                                             object[] args,                                             out object result) {            string procedureName=binder.Name;            object paramObj=GetParameterObject(binder,args);            string storedProcedureName=GenericDAO<T>.StoredProcedureFullName(procedureName);            if(procedureName.StartsWith("Get")) {                result=GetResult(paramObj,storedProcedureName);            } [ ... ] }}

GetAll()GetPeopleByRole()

x 500

”GetAll””GetPeopleByRole”

x 500

torsdag 6 mars 14

Page 24: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

            dynamic dao = GenericDAO<Domain.Person>.Dispatch();            IEnumerable<Domain.Person> people = dao.GetPeopleByRole(RoleId: 3);            people.Should().NotBeEmpty();

Dynamic name resolution

using System;using System.Collections.Generic;using System.Linq;using System.Dynamic;using Configuration;using Extensions;

namespace Core {    public class Dispatcher<T>:DynamicObject where T:class, new() {[ ... ]    public override bool TryInvokeMember(InvokeMemberBinder binder,                                             object[] args,                                             out object result) {            string procedureName=binder.Name;            object paramObj=GetParameterObject(binder,args);            string storedProcedureName=GenericDAO<T>.StoredProcedureFullName(procedureName);            if(procedureName.StartsWith("Get")) {                result=GetResult(paramObj,storedProcedureName);            } [ ... ] }}

GetAll()GetPeopleByRole()

x 500

”GetAll””GetPeopleByRole”

x 500

torsdag 6 mars 14

Page 25: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Generated proxy classes        protected internal T CreateObject<T>(IDataReader reader,

                                             IEnumerable<string> allowedFields=null) where T:class, new() {

            T proxy=ProxyGenerator.CreateClassProxy<T>(ProxygenerationOptions,

                                                         new LazyLoadingInterceptor<T>());

            foreach(var fieldAndProperty in GetFieldsToPropertiesMap<T>(reader,

                                                         allowedFields)) {

                var value=GetValue(reader[fieldAndProperty.Key],

                                     fieldAndProperty.Value);

                if(value!=null) {

                    GetSetter(fieldAndProperty.Value)(proxy,

                                                      value);

                }

            }

            return proxy;

        }

torsdag 6 mars 14

Page 26: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Generated proxy classes        protected internal T CreateObject<T>(IDataReader reader,

                                             IEnumerable<string> allowedFields=null) where T:class, new() {

            T proxy=ProxyGenerator.CreateClassProxy<T>(ProxygenerationOptions,

                                                         new LazyLoadingInterceptor<T>());

            foreach(var fieldAndProperty in GetFieldsToPropertiesMap<T>(reader,

                                                         allowedFields)) {

                var value=GetValue(reader[fieldAndProperty.Key],

                                     fieldAndProperty.Value);

                if(value!=null) {

                    GetSetter(fieldAndProperty.Value)(proxy,

                                                      value);

                }

            }

            return proxy;

        }

torsdag 6 mars 14

Page 27: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Generated proxy classesnamespace Support {

    public class LazyLoadingInterceptor<T>:BaseInterceptor,IInterceptor where T:class, new() {

[ ... ]

        public void Intercept(IInvocation invocation) {

            object proxy=invocation.Proxy;

            // Get the target property access method

            var target=invocation.MethodInvocationTarget;

            string propertyName=GetPropertyName(target.Name);

            if(target.Name.StartsWith("get_")) {

                if(!IsPropertyLoaded(propertyName)) {

                    // Ignore the returned enumeration of elements from Prefetcher<T> as it is just the original sequence with properties set

                    Prefetcher<T>.FetchRelatedProperty(new List<T>() { proxy as T },typeof(T).GetProperty(propertyName));

                    SetPropertyLoaded(propertyName);

                }

            } else {

                // Setter invocation: update "property loaded" map with indication of whether non-default value set

                var setterValue=invocation.GetArgumentValue(0);

                SetPropertyLoaded(propertyName,setterValue!=setterValue.GetType().DefaultValue());

            }

            invocation.Proceed();

        }

    }

}

torsdag 6 mars 14

Page 28: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Generated proxy classesnamespace Support {

    public class LazyLoadingInterceptor<T>:BaseInterceptor,IInterceptor where T:class, new() {

[ ... ]

        public void Intercept(IInvocation invocation) {

            object proxy=invocation.Proxy;

            // Get the target property access method

            var target=invocation.MethodInvocationTarget;

            string propertyName=GetPropertyName(target.Name);

            if(target.Name.StartsWith("get_")) {

                if(!IsPropertyLoaded(propertyName)) {

                    // Ignore the returned enumeration of elements from Prefetcher<T> as it is just the original sequence with properties set

                    Prefetcher<T>.FetchRelatedProperty(new List<T>() { proxy as T },typeof(T).GetProperty(propertyName));

                    SetPropertyLoaded(propertyName);

                }

            } else {

                // Setter invocation: update "property loaded" map with indication of whether non-default value set

                var setterValue=invocation.GetArgumentValue(0);

                SetPropertyLoaded(propertyName,setterValue!=setterValue.GetType().DefaultValue());

            }

            invocation.Proceed();

        }

    }

} Intercept dynamically intercepts method invocations so that properties that are not loaded are fetched

from the databasetorsdag 6 mars 14

Page 29: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

" " public String Name { get; set;}" " public String Age { get; set;}

" " [SP("emp_GetEmployment")]" " [ForeignKey("PersonId")]" " public virtual ICollection<Employment> Employments { get; set;}

torsdag 6 mars 14

Page 30: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

" " public String Name { get; set;}" " public String Age { get; set;}

" " [SP("emp_GetEmployment")]" " [ForeignKey("PersonId")]" " public virtual ICollection<Employment> Employments { get; set;}

torsdag 6 mars 14

Page 31: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

" " public String Name { get; set;}" " public String Age { get; set;}

" " [SP("emp_GetEmployment")]" " [ForeignKey("PersonId")]" " public virtual ICollection<Employment> Employments { get; set;}

torsdag 6 mars 14

Page 32: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

" " public String Name { get; set;}" " public String Age { get; set;}

" " [SP("emp_GetEmployment")]" " [ForeignKey("PersonId")]" " public virtual ICollection<Employment> Employments { get; set;}

torsdag 6 mars 14

Page 33: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

GenericDAO<Person>.Configure("per_GetPeopleWithAddress").By(x => { x.ScanForRelatedTypes(GenericDAO.FetchRelatedObjectsPolicy.ScanFields); });

Scan result set for field names that match properties of related objects

torsdag 6 mars 14

Page 34: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

GenericDAO<Person>.Configure("GetPeopleByRole").By(x => { x.Map("PerId").To(p => p.Id); x.Include<ContactInfo>().By(y => { y.Map("ContactPrivateId").To(c => c.Id); y.Map("PrivateMobile").To(c => c.Mobile); y.Map("PrivateEmail").To(c => c.Email); y.Through(p => p.PrivateContact); }); x.Include<ContactInfo>().By(y => { y.Map("ContactCompanyId").To(c => c.Id); y.Map("CompanyMobile").To(c => c.Mobile); y.Map("CompanyEmail").To(c => c.Email); y.Through(p => p.CompanyContact); }); x.Include<Address>(); });

Map each row in the result set to a main Person object, 2x ContactInfo and an Address

torsdag 6 mars 14

Page 35: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

per_GetPersonsByRole()

torsdag 6 mars 14

Page 36: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

per_GetPersonsByRole()

PerId ContactPrivateId PrivateMobile PrivateEmail ContactCompanyId CompanyMobile CompanyEmail

3 14 070-123456 [email protected] 15 073-567890 [email protected]

Id StreetAddress City

20 1 Infinite loop Götene

torsdag 6 mars 14

Page 37: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

per_GetPersonsByRole()

PerId ContactPrivateId PrivateMobile PrivateEmail ContactCompanyId CompanyMobile CompanyEmail

3 14 070-123456 [email protected] 15 073-567890 [email protected]

Id StreetAddress City

20 1 Infinite loop Götene

Id: 3PrivateContactCompanyContactAddress

Person

Id:14Mobile: "070-123456"Email: "[email protected]"

ContactInfo

Id: 20StreetAddress: "1 Infinite loop"City: "Götene"

Address

Id: 15Mobile: "073-567890"Email: "[email protected]"

ContactInfo

torsdag 6 mars 14

Page 38: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

per_GetPersonsByRole()

PerId ContactPrivateId PrivateMobile PrivateEmail ContactCompanyId CompanyMobile CompanyEmail

3 14 070-123456 [email protected] 15 073-567890 [email protected]

Id StreetAddress City

20 1 Infinite loop Götene

Id: 3PrivateContactCompanyContactAddress

Person

Id:14Mobile: "070-123456"Email: "[email protected]"

ContactInfo

Id: 20StreetAddress: "1 Infinite loop"City: "Götene"

Address

Id: 15Mobile: "073-567890"Email: "[email protected]"

ContactInfo

torsdag 6 mars 14

Page 39: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

y.Map("ContactCompanyId").To(c => c.Id);

torsdag 6 mars 14

Page 40: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

        public void To<T1>(Expression<Func<T,T1>> propertySelector)        {            var selectorExpression = (MemberExpression) propertySelector.Body;            var prop = (PropertyInfo) selectorExpression.Member;            Configurator.CustomFieldsToPropertiesMap[FieldName]=prop;        }

y.Map("ContactCompanyId").To(c => c.Id);

torsdag 6 mars 14

Page 41: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Markup and configuration

        public void To<T1>(Expression<Func<T,T1>> propertySelector)        {            var selectorExpression = (MemberExpression) propertySelector.Body;            var prop = (PropertyInfo) selectorExpression.Member;            Configurator.CustomFieldsToPropertiesMap[FieldName]=prop;        }

y.Map("ContactCompanyId").To(c => c.Id);

FieldName is the name of the field returned in the result set (ContactCompanyId)

torsdag 6 mars 14

Page 42: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

https://github.com/olale/GenericDAO

torsdag 6 mars 14

Page 43: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

Expression Generationhttp://msdn.microsoft.com/en-us/library/bb882637.aspx

torsdag 6 mars 14

Page 44: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

torsdag 6 mars 14

Page 45: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

Return an expression tree that accepts T and returns a boolean

torsdag 6 mars 14

Page 46: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

Node that refers to the parameter x

torsdag 6 mars 14

Page 47: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

Node that refers to the constant false

torsdag 6 mars 14

Page 48: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

x == arg

torsdag 6 mars 14

Page 49: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

for all values of arg in args

torsdag 6 mars 14

Page 50: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

combined with ”||” (OrElse)

torsdag 6 mars 14

Page 51: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

public Expression<Func<T,Boolean>> CreateFilterExpression<T>(params T[] args) { var x = "x"; var paramExp = Expression.Parameter(typeof(T), x); Expression t = Expression.Constant(false); return Expression.Lambda<Func<T,Boolean>>(args.Aggregate(t, " " " " " " " (expr, arg) => " " " " " " " Expression.OrElse(Expression.Equal(paramExp, Expression.Constant(arg)), " " " " " " " " " expr)), " " " " " new ParameterExpression[] { paramExp }); }

torsdag 6 mars 14

Page 52: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

torsdag 6 mars 14

Page 53: Reflection in C# - IDATDDD05/lectures/slides/F03... · 2014-03-06 · Database Interface Layer UI Model torsdag 6 mars 14. 1 Domain class - 1 DAO Service Layer Data Access Layer

torsdag 6 mars 14