亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

分享動態拼接Expression表達式組件及原理

2019-11-17 02:17:24
字體:
來源:轉載
供稿:網友

分享動態拼接ExPRession表達式組件及原理

前言

LINQ大家都知道,用起來也還不錯,但有一個問題,當你用Linq進行搜索的時候,你是這樣寫的

  1. var query = from user in db.Set<User>()
  2. where user.Username == "xxxx"
  3. select user;

OK,看起來很好,不過····如果你要進行動態搜索的話··呵呵!其實方法還是挺多,只不過繞大彎

動態搜索是什么?順便介紹下,假如你做了一個表格頁面,有用戶名、注冊時間、等級三列,你希望實現動態組合搜索,只有當用戶指定了要以用戶名搜索的時候才把用戶名這一列加入搜索條件,傳統的sql是這么干的

  1. string sql="select * from user ";
  2. if(userName!="")
  3. {
  4. sql+=" Where Username="+userName
  5. }

聲明:只做示例,能不能運行不重要!(上面的代碼一般情況下必須是有問題的

那你用linq能不能這么干呢?呃····向下面這樣

  1. var query = from user in db.Set<User>()
  2. select user;
  3. var userName = string.Empty;
  4. if(!string.IsNullOrWhiteSpace(userName))
  5. {
  6. query = query.Where(x => x.Username == userName);
  7. }

對,是可以這樣,但在實際項目中一般是不會直接返回IQueryable接口的,也就沒辦法這么做。

所以,動態拼接linq就應運而生了,而linq的實質是表達式樹,大家可以看IQueryable的Where擴展方法的簽名,是以Expression開頭的。

組件介紹及使用

封裝的最初目的,也是給自己用。我是懶人,所以我會把組件搞得越簡單越好,下面是一個完整的使用示例

  1. TestDataContext db = new TestDataContext();
  2. var builder = new ExpressionBuilder<User>();//實例化組件,User是什么下面說
  3. var filters = new List<SqlFilter>();
  4. filters.Add(SqlFilter.Create("Id", Operation.Equal, 1)); //添加User的Id屬性值等于1的搜索條件
  5. filters.Add(SqlFilter.Create("LastLoginDate", Operation.GreaterThan, DateTime.Now));//添加User的LastLoginDate屬性值大于現在的搜索條件
  6. filters.Add(SqlFilter.Create("Username", Operation.Like, "aaaa"));//添加User的Username屬性值like "aaaaa"的搜索條件
  7. filters.Add(SqlFilter.Create("Id", Operation.In, new int[] { 1, 2, 3 }));//添加User的Id屬性值在1、2、3之中的搜索條件,當Operation為In的時候,最后一個參數必須為集合
  8. filters.Add(SqlFilter.Create("PassWord", Operation.NotEqual, "1"));
  9. filters.Add(SqlFilter.Create("Status", Operation.In, new int[] { 1 }));
  10. var where = builder.Build(filters, new Dictionary<string, string>());//根據上面的條件,拼接出表達式樹
  11. var results = db.Set<User>().Where(where).ToList();//地球人都知道

上面的代碼拼接出來表達式樹是這樣的

  1. var ids=new int[]{1,2,3};
  2. var status=new int[]{1};
  3. db.Set<User>().Where(x => x.Id == 1 && x.LastLoginDate > DateTime.Now && ids.Contains(x.Id) && x.Username.Contains("aaaa") && x.Password != "1" && status.Contains(x.Status));

注釋已經說得比較清楚了,但第2行和第10行需要特別解釋一下,第10行的Build方法原型如下

  1. public Expression<Func<TParameter, bool>> Build(IList<SqlFilter> filters, Dictionary<string, string> filterNameMap)

返回值是一個Expression<Func<TParameter,bool>>類型的,其中有一個泛型參數,這個參數就是第2行實例化的時候傳的User,在使用的時候,必須保證添加的每一個搜索條件的屬性在User類里面有。

為什么要這樣設計呢?這個感覺一下子說不清楚,等下講原理的時候說

另外還可以看到有個filterNameMap的參數,這個主要是用來進行屬性名的轉換的,一般用于外鍵。簡單說一下我當時的設計意圖。

例如,有一個列表,展示的是權限系統中的角色信息,有角色名、描述、擁有的功能三列,其中第三列內容是來自功能表中的,其他是來自角色表的。

一般情況下可能會將第三列的屬性名設置為Privileges,然后類型是string型,但如果說用戶要按角色擁有的功能進行搜索,你不可能按字符串過濾吧?一般是按照功能Id也就是PrivilegeId過濾。

因為我用的是ExtJs(沒用過這個的直接跳過這一段吧),所以問題來了,extjs傳給我的參數名是Privileges,值是一個集合,因為我的Model類屬性名是這個,但我后臺用于過濾的真正屬性是PrivilegeId,所以我需要將Privileges映射到PrivilegeId,告訴ExpressionBuilder,如果遇到了Privileges屬性名的搜索條件,就將屬性名換成PrivilegeId進行拼接

為了方便理解,下面是SqlFilter的源碼,很簡單

  1. public class SqlFilter
  2. {
  3. public static SqlFilter Create(string propertyName, Operation operation, object value)
  4. {
  5. return new SqlFilter()
  6. {
  7. Name = propertyName,
  8. Operation = operation,
  9. Value = value
  10. };
  11. }
  12. /// <summary>
  13. /// 字段名
  14. /// </summary>
  15. public string Name { get; set; }
  16. /// <summary>
  17. /// 搜索操作,大于小于等于
  18. /// </summary>
  19. public Xinchen.DbUtils.Operation Operation { get; set; }
  20. /// <summary>
  21. /// 搜索參數值
  22. /// </summary>
  23. public object Value { get; set; }
  24. }

下面是Operation的

  1. public enum Operation
  2. {
  3. GreaterThan,
  4. LessThan,
  5. GreaterThanOrEqual,
  6. LessThanOrEqual,
  7. NotEqual,
  8. Equal,
  9. Like,
  10. In
  11. }

組件原理

還真沒把握能說清楚···

其實就是拼接表達式樹的原理

  1. //假如我們要拼接x=>x.Id==1,假如x的類型為User
  2. var parameterExp = Expression.Parameter(typeof(User), "x");
  3. //結果是這樣:x=>,x是變量名
  4. var propertyExp = Expression.Property(parameterExp, "Id");
  5. //結果是這樣:x=>x.Id,這句是為了構建訪問屬性的表達式
  6. //上面這句第一個參數是你要取屬性的對象表達式。我們要拼的表達式是x=>x.Id==1,==1這塊先不管,其實就是x=>x.Id,那么其實我們就是對x進行取屬性值,而x是parameterExp,所以第一個參數是parameterExp,第二個參數好說,就是屬性名
  7. var constExp = Expression.Constant(1);
  8. //結果是··沒有結果,構建一個常量表達式,值為1(LINQ的世界,一切皆表達式樹)
  9. //馬上就是關鍵的一步了
  10. var body = Expression.Equal(propertyExp, constExp);
  11. //結果是:x=>x.Id==1,這個··還需要解釋么,很簡單,不是么。創建一個相等的表達式,然后傳入左邊和右邊的表達式
  12. //當然到這兒還不能用,還需要繼續
  13. var lambda = Expression.Lambda<Func<User, bool>>(body, parameterExp);
  14. //這句和第二句是我學的時候最難理解的兩個地方。這句是將我們的成果封裝成能用的,第一個參數就是我們的成果,第二個參數是實現這個成果所需要的參數,那當然是parameterExp,然后泛型參數Func<User,bool>就是我們想把這個表達式封裝成什么樣的東西,此時,lambda的類型就是Expression<Fun<User,bool>>,這個時候就能用了

這是一個相當簡單的表達式樹,注釋寫得很清楚,下面來個復雜的

  1. //假如我們要拼接x=>x.Username.Contains("aaa"),假如x的類型為User
  2. var parameterExp = Expression.Parameter(typeof(User), "x");
  3. var propertyExp = Expression.Property(parameterExp, "Username");
  4. //上面兩句不再介紹
  5. var containsMethod = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
  6. //因為我們要拼接的表達式中調用了string類型的Username的Contains方法,所以反射獲取string類型的Contains方法
  7. var constExp = Expression.Constant("aaa");
  8. //不再解釋
  9. var containsExp = Expression.Call(propertyExp, containsMethod, constExp);
  10. //結果是:x=>x.Username.Contains("aaa"),第一個參數,是要調用哪個實例的方法,這里是propertyExp,第二個是調用哪個方法,第三個是參數,理解了上一個示例,這個應該不難理解
  11. var lambda = Expression.Lambda<Func<User, bool>>(containsExp, parameterExp);
  12. //不再解釋

可以看到,第一句都是取了User的類型,所以我在設計ExpressionBuilder的使用了泛型,以供傳入這個參數

原理就到這兒吧,要看更多的示例就直接看源碼吧

后記

繼續廣告···要了解相關技術的請進QQ群74522853,答案XLinq


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
色吧影院999| 91精品久久久久久久久久| 亚洲欧美成人精品| 精品国产乱码久久久久久虫虫漫画| 国产精品视频不卡| 欧美俄罗斯乱妇| 久久久久久久一区二区三区| 亚洲自拍偷拍视频| 91精品久久久久久久| 国产精品亚洲精品| 免费99精品国产自在在线| 亚洲欧美在线看| 亚洲自拍偷拍第一页| 久久精品国产一区二区电影| 国产日产久久高清欧美一区| 国内精品模特av私拍在线观看| 欧美丰满片xxx777| 66m—66摸成人免费视频| 日韩av在线天堂网| 国产精品成人一区| 一区二区三区久久精品| 久久精品国产精品亚洲| 97av在线视频| 亚洲欧洲一区二区三区在线观看| 欧美日韩国产第一页| 国产在线精品自拍| 亚洲精品女av网站| 欧美丝袜一区二区| 美女久久久久久久| 中文字幕在线日韩| 超碰日本道色综合久久综合| 久久久这里只有精品视频| 国产婷婷97碰碰久久人人蜜臀| 亚洲欧美在线免费| 黄色一区二区在线| 亚洲国产精品资源| 亚洲自拍在线观看| 性欧美办公室18xxxxhd| 日本19禁啪啪免费观看www| 日韩中文字幕视频在线| 高清视频欧美一级| 日韩精品在线免费| 久久久亚洲国产| 日韩av片电影专区| 欧美另类第一页| 欧美精品videosex极品1| 欧美性感美女h网站在线观看免费| 911国产网站尤物在线观看| 国产日本欧美一区二区三区| 国产欧美久久久久久| 亚洲aaaaaa| 亚洲电影成人av99爱色| 国产成人精品在线播放| 久久久久久久久久久人体| 91理论片午午论夜理片久久| 日韩一区二区欧美| 日韩av最新在线观看| 欧美中文在线观看| 欧美一区二区三区……| 亚洲自拍偷拍色图| 午夜精品理论片| 欧美高清自拍一区| 午夜精品福利视频| 成人444kkkk在线观看| 国产69精品久久久| 蜜臀久久99精品久久久无需会员| 欧美超级免费视 在线| 国产精品久久久久久五月尺| 狠狠色噜噜狠狠狠狠97| 国产精品一香蕉国产线看观看| 欧美精品免费在线| 亚洲精品久久久久久久久| 亚洲一区二区三区sesese| 日韩有码片在线观看| 91精品国产99| 亚洲一区二区三区在线免费观看| 欧美超级乱淫片喷水| 亚洲欧美国产一区二区三区| 91探花福利精品国产自产在线| 一区二区成人av| 亚洲精品久久在线| 日韩av网址在线观看| 亚洲精品久久久久中文字幕二区| 亚洲精品久久在线| 成人久久一区二区三区| 亚洲专区国产精品| 57pao成人国产永久免费| 夜色77av精品影院| 日本不卡视频在线播放| 国产亚洲精品一区二区| 午夜精品国产精品大乳美女| 亚洲综合日韩中文字幕v在线| 欧美性一区二区三区| 欧美日韩视频在线| 久久久电影免费观看完整版| 免费91在线视频| 人人澡人人澡人人看欧美| 日韩精品日韩在线观看| 国内精品模特av私拍在线观看| 久久99亚洲精品| 97国产一区二区精品久久呦| 91影视免费在线观看| 国产国语videosex另类| 日韩欧美在线第一页| 国产精彩精品视频| 国产成人精品久久亚洲高清不卡| 91欧美精品午夜性色福利在线| 亚洲综合一区二区不卡| 色综合久久悠悠| 欧美亚洲国产日韩2020| 亚洲毛片在线免费观看| 欧美怡红院视频一区二区三区| 日韩a**中文字幕| 在线丨暗呦小u女国产精品| 久久久国产精品免费| 色无极影院亚洲| 欧美亚洲激情视频| 亚洲精品网址在线观看| 国产99视频在线观看| 欧美性高潮床叫视频| 一本色道久久综合狠狠躁篇怎么玩| 亚洲美女av黄| 57pao成人国产永久免费| 中文字幕久热精品视频在线| 中文字幕久久精品| 欧美重口另类videos人妖| 成人性生交大片免费看小说| 日韩一二三在线视频播| 97人人爽人人喊人人模波多| 欧美日韩性生活视频| 欧美天天综合色影久久精品| 日韩精品在线观看一区| 亚洲精品国产精品国产自| 日韩欧美在线播放| 久久午夜a级毛片| 久久亚洲精品中文字幕冲田杏梨| 亚洲丁香婷深爱综合| 在线播放日韩专区| 久久久国产影院| 黑人巨大精品欧美一区免费视频| 亚洲精品自产拍| 亚洲国产中文字幕久久网| 久久综合国产精品台湾中文娱乐网| 自拍偷拍亚洲区| 久久91精品国产91久久跳| 韩曰欧美视频免费观看| 国产精品三级久久久久久电影| 久久久久久久亚洲精品| 26uuu亚洲伊人春色| 国产一区二区三区久久精品| 成人黄色av播放免费| 日韩免费av片在线观看| 亚洲国产精品久久久久| 久久久久久国产| 亚洲精品98久久久久久中文字幕| 欧美大片在线看| 欧美裸体视频网站| 欧美日韩第一页| 欧美在线视频观看| 91视频8mav| 国产91在线高潮白浆在线观看| 国产成人精品在线视频| 亚洲国产精品一区二区三区| 91老司机精品视频|