The previous insert, UPDATE, DELETE optimized ORM, but populating the database with values in the entity class is not optimized. In addition, Bo friends in the online consultation said that you are all query all fields, and his needs are on-demand query fields, not one-time out all the fields, here I ask this friend to wait patiently, this will be mentioned in later chapters. This time we optimize the datareader->entity, the value of the database mapping to the entity class, we commonly used to have two methods, the first is to use the Emit method, the second is to use expression tree expressions, the two schemes differ little in performance, But the second is easier to do than the first, where I use expression tree expressions to perform entity class conversion operations.
Let's start by looking at how expression expressions convert DataReader to object:
NULL ; ExpressionNew User () { = R.getint32 (0), = R.getdatetime ( 1 ), = r.getstring (2), }; var func = expr.compile (); Func (reader);
In the new user when the object is initialized to assign values to the property, and in the actual project we will encounter more complex, such as to determine whether it is dbnull, or the conversion will be wrong, here I define a getvalue<t> (int i) method, specifically to do the value operation.
classDbfieldreader {PrivateIDataReader Reader; PublicDbfieldreader (IDataReader reader) { This. Reader =reader; } PublicT getvalue<t> (intindex) { ObjectValue =Reader. GetValue (index); if(Value = =DBNull.Value)return default(T); return(T) reader. GetValue (index); } }
Now the code is modified,
IDataReader reader =NULL; Dbfieldreader FR=NewDbfieldreader (reader); Expression<func<dbfieldreader, user>> expr = (r) = =NewUser () {UserId= r.getvalue<int> (0), Createdtime= R.getvalue<datetime> (1), Email= r.getvalue<string> (2), }; varFunc =Expr.compile (); Func (FR);
Is it a lot more concise? Transfer the judgment code to the Dbfieldreader class, now we are going to convert this method into a generic entity class, first to decompose expression expressions (such as throwing up errors, begging the great God).
The first step defines the parameter, type Dbfieldreader, parameter name: R
ParameterExpression parexpr = Expression.parameter (typeof"R");
In the second step, call the constructor of the user class with the following code:
var newexpr = expression.new (type. GetConstructors (). First ());
Merge these 2 expressions and run the results:
Expression<func<dbfieldreader, user>> expr = (Expression<func<dbfieldreader, User>>) Expression.lambda (newexpr, parexpr);
The basic prototype came out, now to do is to assign value to the attribute, how come? First, a simple one is to give a fixed value.
var userid = Expression.bind (type. GetProperty ("UserId"), Expression.constant (1typeof(int))) ;
This is equivalent to the assignment operation of UserID = 1, which continues to merge expressions:
varType =typeof(User); ParameterExpression parexpr= Expression.parameter (typeof(Dbfieldreader),"R"); varnewexpr =expression.new (type. GetConstructors (). First ()); varUserID = Expression.bind (type. GetProperty ("UserId"), Expression.constant (1,typeof(int))); varCreatedtime = Expression.bind (type. GetProperty ("Createdtime"), Expression.constant (DateTime.Now,typeof(DateTime))); varinit =Expression.memberinit (newexpr, UserID, createdtime); Expression<func<dbfieldreader, user>> expr = (Expression<func<dbfieldreader, user>>) Expression.Lambda (init, parexpr);
After the constant assignment is not a problem, the following method is called.
var typeof " GetValue " && C.isgenericmethod). First (); var callexpr = Expression.call (parexpr, method. MakeGenericMethod (typeof(int.)), Expression.constant (0));
var UserID = Expression.bind (type. GetProperty ("UserId"), callexpr);
This sentence is equivalent to r.getvalue<int> (0);
Get the GetValue method first, then call MakeGenericMethod to generate the generic method, Expression.constant (0) is the parameter value.
Full version of the code:
IDataReader reader =NULL; Dbfieldreader FR=NewDbfieldreader (reader); varentitymapping = attributemapping.get<user>(); ParameterExpression parexpr= Expression.parameter (typeof(Dbfieldreader),"R"); varnewexpr =expression.new (EntityMapping.EntityType.GetConstructors (). First ()); varMETHOD =typeof(Dbfieldreader). GetMethods (). Where (c = c.name = ="GetValue"&&C.isgenericmethod). First (); List<MemberBinding> memberbindings =NewList<memberbinding>(); intindex =0; foreach(varIteminchentitymapping.members) {varcallexpr =Expression.call (parexpr, method. MakeGenericMethod (item. Member.propertytype), Expression.constant (index)); varMemberassignment =Expression.bind (item. Member, callexpr); Memberbindings.add (memberassignment); Index++; } varinit =Expression.memberinit (newexpr, memberbindings); Expression<func<dbfieldreader, user>> expr = (Expression<func<dbfieldreader, user>>) Expression.Lambda (init, parexpr);
Of course we also need to modify the SQL statement, not with the SELECT * syntax, but to use the syntax of select Userid,email...from
The final code code download:
Http://files.cnblogs.com/files/sobaby/ORM05.zip
Step by step to implement your own ORM (v)