34
loading...
This website collects cookies to deliver better user experience
public class Student
{
public int Id { get; set; }
public string Name { set; set; }
public virtual ICollection<Class> Classes { get; set; }
}
public class Class
{
public int Id { get; set; }
public string Name { set; set; }
public virtual ICollection<Class> Students { get; set; }
}
public class StudentModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ClassModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<StudentModel> Students { get; set; }
}
/* Utilizing LINQ to Entities you can see
* how we have to specify StudentModels mappings
* in the class models select statement
*/
return database.Classes
.Select(cl => new ClassModel
{
Id = cl.Id
Students = cl.Students.Select(st => new StudentModel
{
Id = st.Id
}
})
.ToList()
// Or we could pull all the data in order to get a cleaner modeling
return database.Classes
.ToList()
.Select(cl => new ClassModel(cl))
.ToList()
public class ClassModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<StudentModel> Students { get; set; }
/*
* Here we define how a the source of
* the object is bound to this object
* The passed in expression is the parameter of
* select statement, in this case will be the type of Class
*/
public static MemberAssignment[] Assignments(Expression param)
{
return new MemberAssignment[]
{
/*
* Here we are saying we want to bind the property Id on
* ClassModel to the property Id
* on the passed param (Class)
*/
Expression
.Bind(
typeof(ClassModel).GetProperty("Id"),
Expression.Property(param, "Id")
),
// Same for name as above
Expression
.Bind(
typeof(ClassModel).GetProperty("Name"),
Expression.Property(param, "Name")
),
/*
* Here it gets a bit tricker, we are still binding
* students to students but we need to get a list
* (See StudentModel)
*/
Expression
.Bind(
typeof(ClassModel).GetProperty("Students"),
StudenModel.InitList(
Expression.Property(param, "Students")
)
)
};
}
/*
* Here is how the ClassModel is "newed" it creates
* a new ClassModel with a parameterless constructor
* and binds all the known bindings to body, generating
* new ClassModel { // Insert Bindings }
*/
public static Expression<Func<Class, ClassModel>> Init()
{
// Define the soruce of the expressions type
// in this case class dbo
ParameterExpression param =
Expression.Parameter(typeof(Class), "source");
// New the class model using the above bindings
MemberInitExpression init =
Expression.MemberInit(
Expression.New(typeof(ClassModel)),
Assignments(param)
);
// Return the lambda which is
// source => new ClassModel { Id = source.Id, Name = source.Name }
return Expression.Lambda<Func<Class, ClassModel>>(init, param);
}
}
public class StudentModel
{
public int Id { get; set; }
public string Name { get; set; }
// Same as the class model define the assignments
public static MemberAssignment[] Assignments(Expression param)
{
return new MemberAssignment[]
{
/*
* Here we are saying we want to bind the property Id
* on StudentModel to the property Id
* on the passed param (Student)
*/
Expression.Bind(
typeof(StudentModel).GetProperty("Id"),
Expression.Property(param, "Id")
),
// Same for name as above
Expression.Bind(
typeof(StudentModel).GetProperty("Name"),
Expression.Property(param, "Name")
),
};
}
// Just init a single StudentModel
public static Expression<Func<Student, StudentModel>> Init()
{
ParameterExpression param =
Expression.Parameter(typeof(Student), "source");
MemberInitExpression init =
Expression.MemberInit(
Expression.New(typeof(StudentModel)),
Assignments(param)
);
return Expression.Lambda<Func<Student, StudentModel>>(init, param);
}
/*
* This is a bit out of the scope of the article,
* but I wanted to include it to show the capablities
* Basically here we are generating the sub tree
* that will select and to list all the students in the class
*/
public static MethodCallExpression InitList(Expression param)
{
/*
* Just like the member init we have to bind
* the source of the select statement
* to the type of Student
*/
ParameterExpression studentParam =
Expression.Parameter(typeof(Student), "source");
/*
* Next we new a student model with the assigments from above
* So now we have
* new StudentModel{ Id = source.Id, Name = soruce.Name }
*/
MemberInitExpression studentModelInit =
Expression.MemberInit(
Expression.New(typeof(StudentModel)),
Assignments(studentParam)
);
/*
* And finally smack these two together in a
* lambda statement to generate
* source =>
* new StudentModel{ Id = source.Id, Name = soruce.Name }
*/
LambdaExpression lambda =
Expression.Lambda<Func<Student, StudentModel>>
(studentModelInit, studentParam);
/*
* Now we have to specify we are making a call
* to the select statement and specify the types
*/
MethodCallExpression studentSelect = Expression.Call(
null,
GetSelect().MakeGenericMethod(new Type[] {
// Our select "in"
typeof(Student),
// Our select "out"
typeof(StudentModel)
}),
new Expression[] {
// The binding param (a list of students)
param,
// The lamda body from above
lambda
});
// And finally to list it to get all of them
return Expression.Call(
typeof(Enumerable),
"ToList",
// Same here define the type of the out
new Type[] { typeof(StudentModel) },
// The "body" of the to list
studentSelect
);
}
}
return database.Classes
.Select(ClassModel.Init())
.ToList();
return database.Students
.Select(StudentModel.Init())
.ToList()
public class StudentModel
{
public int Id { get; set; }
public string Name { get; set; }
/*
* All we need to do is setup the init function
* I like to use From<Source> syntax
*/
public static Func<Expression, MemberAssignments[]> FromStudent()
param =>
new MemberAssigment[] {
// Directly bind from source to result on both properties
param.DirectBind<StudentModel>("Id"),
param.DirectBind<StudentModel>("Name")
};
}
public class ClassModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<StudentModel> Students { get; set; }
public static Func<Expression, MemberAssignments[]> FromClass()
param =>
new MemberAssigment[] {
// Directly bind from source to result on both properties
param.DirectBind<StudentModel>("Id"),
param.DirectBind<StudentModel>("Name"),
/*
* Creates a list of StudentModels
* We have to specify the binding model, the source,
* and the result in order to generate the list mapping
*/
param.BindSelectedList<ClassModel, Class, StudentModel>
("Students", "Students", StudentModel.FromStudent)
};
}
// How to query
database.Class
.Select(ClassModel.FromClass.Model<Class, ClassModel>())
.ToList()