不成文的,我这两天学习Expression的零散心得
2012-01-03 18:32
281 查看
对于Expression总感觉那么深奥,虽然现在也是。但是终究是略窥门径了。
1. 一个Patient有多个Case,一个Case有多个Sample。
2. 一个Patient有多个PatientCustomTableRecord,一个Case有多个CaseCustomTableRecord,一个Sample有多个SampleCustomTableRecord。
3. CustomTable的结构是:一个CustomTableIndex有多个CustomTableColumn。每一个CustomTableRecord对应一个Column,值类型有5种,int, double, string, datetime, 数据字典。如果值来源于数据字典的话还要记录数据字典ID。
4. 每个CustomTableRecord有个属性是RecordIndex,表明该值是第几条记录。
所以唯一确定一条CustomRecord的方法是,锁定该Record所在的Column,根据该Column的值类型,锁定值。
5. 具体条件:有个CustomTableIndex叫IHC,属于Sample的。其中有两列:IHC指标名称,IHC指标结果
期待查询:
1. 具有IHC指标名称=IHC1 且IHC指标结果=20%的Sample
2. 具有条件1那样Sample的Case
3. 具有条件2那样的Patient
首先说,如果方法是带T的泛型,那么在call的时候必须指定Type[],如果有多个Type,那么那个Type[]里的成员就有多少个。
因此我调用第一种Any的时候会这么写:(2/29更正:这实际上是第二种Any)
这个语句返回的是一个bool型的Expression。其中leftwhere是一个IQueryable<SampleCustomTableRecord>类型的Expression。没有任何predicate。就是要找出满足任意leftwhere里面条件的SampleCustomTableRecord。然后用在我之后要用的Where里。
我调用第二种Any的时候会这么写:
这里的temp代表含有当前sample的case的patient的PatientCustomTableRecord集合。Result代表一个lambdaExpression,就是:Expression<Func<TSource, bool>> predicate。定义Lambda的时候,如果泛型,要指定ParameterExpression作为TSource。比如实现这个Lambda:
SCTR => ((SCTR.CHTI.ID == 131) And (SCTR.Column.ID == 73))
SCTR就是那个ParameterExpression:
自我理解:这里的SCTR类似于SQL里面的AS后面的别称,我就叫他委托对象名。
这样就完成了两个Any的调用。
2. 想做join。实现题中查询
为此在论坛上发帖:http://topic.csdn.net/u/20120101/18/a73b5d2f-5d31-4434-aae7-503b0aa25691.html
到现在位置虽没有解决,但是开阔了我的思路。目前我想要的Linq是这样的:
var query=from ain
SampleCustomTableRecordsjoin bin SampleCustomTableRecordson
a.RecordIndexequals b.RecordIndexwhere a.FK1==73&&
a.FK2==131&& b.FK1==74&&
b.FK2=163select a;
可惜这里的join我必须用Queryable的join才能实现,关于这个Join的使用,我google到了一篇文章,现在给他贴过来:
OK - let's say you want to build the following query:
The first step is to translate this into lambda/method syntax. We can do this with LINQPad:(linqpad是个好东东。我得找找)
(Note the cast to the nullable int in the 4th line: this is necessary if the foreign key is nullable).
To build the expression tree manually, we start by building the three lambda expressions in the query. The first two are fairly easy:
The third one requires that we call string.Concat:
Now we can do the join. We must supply the type of each type argument in Join. The Join method is defined as follows:
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>
Therefore, we must supply the type arguments in the order TOuter, TInner, TKey, TResult:
We can test this as follows:
也许对于Expression Linq达人来讲这算不了什么,可对于我来说真的很神奇。现在就差一步了:Join后怎么加Where?Join里肯定有两个委托对象名,我怎么保证这两个对象名还能在Where里面用?这里的Where可不再是Linq里的where了啊。有个哥们跟我一样的问题,给了我思路启发:http://stackoverflow.com/questions/485398/how-to-create-a-join-in-an-expression-tree-for-linq。我何必非得在Join后加Where呢?直接在Join的左右先做Where不就行了?不断join只需要不停滴更换右边的委托对象名就行了
懒得说过程了,直接上代码:这个是想找出满足SampleCustomTableRecord条件的Sample
得到的Expression是类似于这样的:
test:
{Convert(Sample.CustomTableRecords).Where(SampleCustomTableRecord => ((SampleCustomTableRecord.CHTI.ID == 131) And
(SampleCustomTableRecord.Column.ID == 73)))
.Join(Convert(Sample.CustomTableRecords).Where(SCTR1 => ((SCTR1.CHTI.ID == 163) And (SCTR1.Column.ID == 74))),
SampleCustomTableRecord => Convert(SampleCustomTableRecord.RecordIndex),
SCTR1 => Convert(SCTR1.RecordIndex),
(SampleCustomTableRecord, SCTR1) => SampleCustomTableRecord)}
到此为止,成功已有90%。剩下的就是利用Where,Select,Contains,拼接最终步骤,来实现命题的查询了。
就写到这吧,免的日后忘了。记性越来越差了。
helpful link:
http://msdn.microsoft.com/en-us/library/bb896266.aspx
http://msdn.microsoft.com/en-us/library/bb397676.aspx
http://msdn.microsoft.com/en-us/library/bb534644.aspx
http://msdn.microsoft.com/en-us/library/bb882637.aspx
http://blogs.msdn.com/b/mattwar/archive/2007/09/04/linq-building-an-iqueryable-provider-part-vii.aspx 两种方法实现join
2012-2-29补充:
速成的果然不行,时隔不到两个月,我居然看不懂自己的代码了。盯了一个小时又悟出点以前知道但没写到的内容:
1. 我的一个ResultSelector是这样写的:
此处Lambda的定义为:
debug时看到resultSelector变成:
{(SampleCustomTableRecord, SCTR1) => SampleCustomTableRecord}
此时:Lambda的两个Parameter就是
pe_SampleCustomTableRecord=Expression.Parameter(typeof(SampleCustomTableRecord), "SampleCustomTableRecord");
rightpe=Expression.Parameter(typeof(SampleCustomTableRecord), "SCTR" + i);
这里的Func做如下解释:Func<Tin1, Tin2, Tout>. 显然两个In,对应两个委托对象名,即两个ParameterExpression.
Lambda就是(委托对象名)=>{Body真正的函数体}
一,先说我这两天遇到的问题:
条件:1. 一个Patient有多个Case,一个Case有多个Sample。
2. 一个Patient有多个PatientCustomTableRecord,一个Case有多个CaseCustomTableRecord,一个Sample有多个SampleCustomTableRecord。
3. CustomTable的结构是:一个CustomTableIndex有多个CustomTableColumn。每一个CustomTableRecord对应一个Column,值类型有5种,int, double, string, datetime, 数据字典。如果值来源于数据字典的话还要记录数据字典ID。
4. 每个CustomTableRecord有个属性是RecordIndex,表明该值是第几条记录。
所以唯一确定一条CustomRecord的方法是,锁定该Record所在的Column,根据该Column的值类型,锁定值。
5. 具体条件:有个CustomTableIndex叫IHC,属于Sample的。其中有两列:IHC指标名称,IHC指标结果
期待查询:
1. 具有IHC指标名称=IHC1 且IHC指标结果=20%的Sample
2. 具有条件1那样Sample的Case
3. 具有条件2那样的Patient
二,解决方法。
采用动态拼接查询语句的方式。利用Expression.Call, Expression.Lambda等等利用Queryable的Any,Where,Select,Contains等等方法三,阐述一下自己理解的Expression的一些用法:
1. Expression.Call: msdn上有。还总是看不明白。现在拿个例子来解释:
比如我想Call,Queryable的Any方法:去这个类里面看,有两种定义:public static bool Any<TSource>(this IQueryable<TSource> source); public static bool Any<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
首先说,如果方法是带T的泛型,那么在call的时候必须指定Type[],如果有多个Type,那么那个Type[]里的成员就有多少个。
因此我调用第一种Any的时候会这么写:(2/29更正:这实际上是第二种Any)
Expression.Call(typeof(Queryable), "Any", new Type[] { typeof(SampleCustomTableRecord) }, leftwhere)
这个语句返回的是一个bool型的Expression。其中leftwhere是一个IQueryable<SampleCustomTableRecord>类型的Expression。没有任何predicate。就是要找出满足任意leftwhere里面条件的SampleCustomTableRecord。然后用在我之后要用的Where里。
我调用第二种Any的时候会这么写:
Expression temp = Expression.Convert(Expression.PropertyOrField(Expression.PropertyOrField(Expression.PropertyOrField(pe_Sample, "ParentCase"), "ParentPatient"), "CustomTableRecords"), typeof(IQueryable<PatientCustomTableRecord>));
Expression.Call(typeof(Queryable), "Any", new Type[] { typeof(PatientCustomTableRecord) }, temp, result)
这里的temp代表含有当前sample的case的patient的PatientCustomTableRecord集合。Result代表一个lambdaExpression,就是:Expression<Func<TSource, bool>> predicate。定义Lambda的时候,如果泛型,要指定ParameterExpression作为TSource。比如实现这个Lambda:
SCTR => ((SCTR.CHTI.ID == 131) And (SCTR.Column.ID == 73))
SCTR就是那个ParameterExpression:
public static ParameterExpression pe = Expression.Parameter(typeof(SampleCustomTableRecord), "SCTR");
自我理解:这里的SCTR类似于SQL里面的AS后面的别称,我就叫他委托对象名。
//首先找到SCTR.Column.ID属性 Expression cCIDExp = Expression.Property(Expression.Property(pe, "Column"), "ID"); Expression findCCExp = Expression.Equal(cCIDExp, Expression.Constant(73)); //然后锁定数据字典外键 Expression left = Expression.PropertyOrField(Expression.Property(pe, "CHTI"), "ID"); left = Expression.Equal(left, Expression.Constant(131)); //最后实现Lambda委托. 这个委托的最终类型是://Expression<Func<SampleCustomRecord, bool>> Expression rv = Expression.Lambda(Expression.And(left, findCCExp), pe);
这样就完成了两个Any的调用。
2. 想做join。实现题中查询
为此在论坛上发帖:http://topic.csdn.net/u/20120101/18/a73b5d2f-5d31-4434-aae7-503b0aa25691.html
到现在位置虽没有解决,但是开阔了我的思路。目前我想要的Linq是这样的:
var query=from ain
SampleCustomTableRecordsjoin bin SampleCustomTableRecordson
a.RecordIndexequals b.RecordIndexwhere a.FK1==73&&
a.FK2==131&& b.FK1==74&&
b.FK2=163select a;
可惜这里的join我必须用Queryable的join才能实现,关于这个Join的使用,我google到了一篇文章,现在给他贴过来:
OK - let's say you want to build the following query:
from c in Customers join p in Purchases on c.ID equals p.CustomerID select c.Name + " bought a " + p.Description
The first step is to translate this into lambda/method syntax. We can do this with LINQPad:(linqpad是个好东东。我得找找)
Customers .Join ( Purchases, c => (Int32?)(c.ID), p => p.CustomerID, (c, p) => ((c.Name + " bought a ") + p.Description) )
(Note the cast to the nullable int in the 4th line: this is necessary if the foreign key is nullable).
To build the expression tree manually, we start by building the three lambda expressions in the query. The first two are fairly easy:
ParameterExpression customerParam = Expression.Parameter (typeof (Customer), "c"); Expression<Func<Customer, int?>> outerKeySelector = Expression.Lambda<Func<Customer, int?>> ( Expression.Convert (Expression.PropertyOrField (customerParam, "ID"), typeof (int?)), customerParam); ParameterExpression purchaseParam = Expression.Parameter (typeof (Purchase), "p"); Expression<Func<Purchase, int?>> innerKeySelector = Expression.Lambda<Func<Purchase, int?>> ( Expression.PropertyOrField (purchaseParam, "CustomerID"), purchaseParam);
The third one requires that we call string.Concat:
MethodInfo concatThreeItems = typeof (string).GetMethod ("Concat", Enumerable.Repeat (typeof (object), 3).ToArray()); Expression<Func<Customer, Purchase, string>> resultSelector = Expression.Lambda<Func<Customer, Purchase, string>> ( Expression.Call ( concatThreeItems, new Expression[] { Expression.PropertyOrField (customerParam, "Name"), // c.Name Expression.Constant (" bought a "), Expression.PropertyOrField (purchaseParam, "Description") // p.Description }), customerParam, purchaseParam);
Now we can do the join. We must supply the type of each type argument in Join. The Join method is defined as follows:
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>
Therefore, we must supply the type arguments in the order TOuter, TInner, TKey, TResult:
var db = new TypedDataContext(); var join = Expression.Call ( typeof (Queryable), "Join", new Type[] { typeof (Customer), // TOuter, typeof (Purchase), // TInner, typeof (int?), // TKey, typeof (string) // TResult }, new Expression[] { Expression.PropertyOrField (Expression.Constant (db), "Customers"), Expression.PropertyOrField (Expression.Constant (db), "Purchases"), outerKeySelector, innerKeySelector, resultSelector });
We can test this as follows:
Expression.Lambda<Func<IQueryable<string>>> (join).Compile()().Dump();
也许对于Expression Linq达人来讲这算不了什么,可对于我来说真的很神奇。现在就差一步了:Join后怎么加Where?Join里肯定有两个委托对象名,我怎么保证这两个对象名还能在Where里面用?这里的Where可不再是Linq里的where了啊。有个哥们跟我一样的问题,给了我思路启发:http://stackoverflow.com/questions/485398/how-to-create-a-join-in-an-expression-tree-for-linq。我何必非得在Join后加Where呢?直接在Join的左右先做Where不就行了?不断join只需要不停滴更换右边的委托对象名就行了
懒得说过程了,直接上代码:这个是想找出满足SampleCustomTableRecord条件的Sample
else if (item.peRecordType == pe_SampleCustomTableRecord) { //handle the first one, the very beginning on left hand string[] firstsplit = item.SearchConditions[0].FieldTitle.Split(new char[]{'-'}); Expression left = GetCustomPredict(pe_SampleCustomTableRecord, "样本信息", mtype, firstsplit[1], firstsplit[2], item.SearchConditions[0].Condition, item.SearchConditions[0].Value);//子函数用于得到应用于Where条件的Lambda表达式 Expression leftwhere = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(SampleCustomTableRecord) }, sampleCR, left); for (int i = 1; i < item.SearchConditions.Count; i++) { ParameterExpression rightpe = Expression.Parameter(typeof(SampleCustomTableRecord), "SCTR"+i);//由于是同表Join,所以右边的委托对象名需要不停更换 string[] secondsplit = item.SearchConditions[i].FieldTitle.Split(new char[]{'-'}); Expression right = GetCustomPredict(rightpe, "样本信息", mtype, secondsplit[1], secondsplit[2], item.SearchConditions[i].Condition, item.SearchConditions[i].Value); Expression rightwhere = Expression.Call(typeof(Queryable),"Where",new Type[]{typeof(SampleCustomTableRecord)},sampleCR,right); Expression OuterKeySelector = Expression.Lambda<Func<SampleCustomTableRecord, int>>(Expression.Convert(Expression.PropertyOrField(pe_SampleCustomTableRecord, "RecordIndex"), typeof(int)), pe_SampleCustomTableRecord); Expression InnerKeySelector = Expression.Lambda<Func<SampleCustomTableRecord, int>>(Expression.Convert(Expression.PropertyOrField(rightpe, "RecordIndex"), typeof(int)), rightpe); Expression<Func<SampleCustomTableRecord,SampleCustomTableRecord,SampleCustomTableRecord>> resultSelector = Expression.Lambda<Func<SampleCustomTableRecord,SampleCustomTableRecord,SampleCustomTableRecord>>(pe_SampleCustomTableRecord,new ParameterExpression[]{pe_SampleCustomTableRecord,rightpe}); Expression test = Expression.Call(typeof(Queryable), "Join", new Type[] { typeof(SampleCustomTableRecord),//TOuter typeof(SampleCustomTableRecord),//TInner typeof(int),//TKey typeof(SampleCustomTableRecord)//TResult }, new Expression[] { leftwhere, rightwhere, OuterKeySelector,//outerkey InnerKeySelector,//innerkey resultSelector//result???? }); leftwhere = test; } CombinationExpressions.Add(Expression.Call(typeof(Queryable), "Any", new Type[] { typeof(SampleCustomTableRecord) }, leftwhere)); }
得到的Expression是类似于这样的:
test:
{Convert(Sample.CustomTableRecords).Where(SampleCustomTableRecord => ((SampleCustomTableRecord.CHTI.ID == 131) And
(SampleCustomTableRecord.Column.ID == 73)))
.Join(Convert(Sample.CustomTableRecords).Where(SCTR1 => ((SCTR1.CHTI.ID == 163) And (SCTR1.Column.ID == 74))),
SampleCustomTableRecord => Convert(SampleCustomTableRecord.RecordIndex),
SCTR1 => Convert(SCTR1.RecordIndex),
(SampleCustomTableRecord, SCTR1) => SampleCustomTableRecord)}
到此为止,成功已有90%。剩下的就是利用Where,Select,Contains,拼接最终步骤,来实现命题的查询了。
就写到这吧,免的日后忘了。记性越来越差了。
helpful link:
http://msdn.microsoft.com/en-us/library/bb896266.aspx
http://msdn.microsoft.com/en-us/library/bb397676.aspx
http://msdn.microsoft.com/en-us/library/bb534644.aspx
http://msdn.microsoft.com/en-us/library/bb882637.aspx
http://blogs.msdn.com/b/mattwar/archive/2007/09/04/linq-building-an-iqueryable-provider-part-vii.aspx 两种方法实现join
2012-2-29补充:
速成的果然不行,时隔不到两个月,我居然看不懂自己的代码了。盯了一个小时又悟出点以前知道但没写到的内容:
1. 我的一个ResultSelector是这样写的:
Expression<Func<SampleCustomTableRecord, SampleCustomTableRecord, SampleCustomTableRecord>> resultSelector = Expression.Lambda<Func<SampleCustomTableRecord, SampleCustomTableRecord, SampleCustomTableRecord>>(pe_SampleCustomTableRecord, new ParameterExpression[] { pe_SampleCustomTableRecord, rightpe });
此处Lambda的定义为:
// // Summary: // Creates an System.Linq.Expressions.Expression<TDelegate> where the delegate // type is known at compile time. // // Parameters: // body: // An System.Linq.Expressions.Expression to set the System.Linq.Expressions.LambdaExpression.Body // property equal to. // // parameters: // An array of System.Linq.Expressions.ParameterExpression objects to use to // populate the System.Linq.Expressions.LambdaExpression.Parameters collection. // // Type parameters: // TDelegate: // A delegate type. // // Returns: // An System.Linq.Expressions.Expression<TDelegate> that has the System.Linq.Expressions.Expression.NodeType // property equal to System.Linq.Expressions.ExpressionType.Lambda and the System.Linq.Expressions.LambdaExpression.Body // and System.Linq.Expressions.LambdaExpression.Parameters properties set to // the specified values. // // Exceptions: // System.ArgumentNullException: // body is null.-or-One or more elements in parameters are null. // // System.ArgumentException: // TDelegate is not a delegate type.-or-body.Type represents a type that is // not assignable to the return type of TDelegate.-or-parameters does not contain // the same number of elements as the list of parameters for TDelegate.-or-The // System.Linq.Expressions.Expression.Type property of an element of parameters // is not assignable from the type of the corresponding parameter type of TDelegate. public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters);
debug时看到resultSelector变成:
{(SampleCustomTableRecord, SCTR1) => SampleCustomTableRecord}
此时:Lambda的两个Parameter就是
pe_SampleCustomTableRecord=Expression.Parameter(typeof(SampleCustomTableRecord), "SampleCustomTableRecord");
rightpe=Expression.Parameter(typeof(SampleCustomTableRecord), "SCTR" + i);
这里的Func做如下解释:Func<Tin1, Tin2, Tout>. 显然两个In,对应两个委托对象名,即两个ParameterExpression.
Lambda就是(委托对象名)=>{Body真正的函数体}
相关文章推荐
- 不成文的,我这两天学习Expression的零散心得
- 这两天学习nRF51822的心得
- 这两天比较无聊学习了jdbc,以下是我整理的心得
- gdb零散学习心得。
- Hibernate学习心得(一)
- JPA学习总结(搜罗的其他前辈们的知识结晶加上自己的一点点心得)(1)
- 11.27学习心得
- 学习《spring揭秘》心得_1
- E-learning的学习心得
- MapXtreme 2005 学习心得 在地图上创建点/线并显示标注(五)
- Android学习心得(6) --- smali语法学习
- HTTP协议实现文件上传学习心得
- 学习java的一点心得(二)
- Skyline学习心得-web-获取图层树
- 学习心得
- 学习C++心得与值得一看的书
- 学习《TCP/IP详解 卷一协议》第九章的一点心得
- C++学习心得
- Chrome插件开发学习心得(一)之前期开发