<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      背景

        長話短說, 作為開發(fā)人員經(jīng)常需要根據(jù)條件靈活查詢數(shù)據(jù)庫,不管你是用rawsql 還是EFCore, 以下類似偽代碼大家都可能遇到:
      /// <summary> /// 靈活查詢 能耗數(shù)據(jù)表 (rawsql) /// </summary> [Route("all")] [HttpGet]
      public async Task<List<CarEnergyModelEntity>> GetModeParametersAsync(
      [FromQuery]string carVersion, [FromQuery] string carId, [FromQuery] string
      userId, [FromQuery]string soVersion, [FromQuery] string configVersion,
      [FromQuery]string ConfigContent ) { StringBuilder strWhere = new StringBuilder("
      1=1"); if (!string.IsNullOrEmpty(carVersion)) strWhere.Append($" and
      car_version='{carVersion}'"); if (!string.IsNullOrEmpty(carId))
      strWhere.Append($" and car_id_='{carId}'"); if (!string.IsNullOrEmpty(userId))
      strWhere.Append($" and user_id='{userId}'"); if (!string
      .IsNullOrEmpty(soVersion)) strWhere.Append($" and so_version='{soVersion}'"); if
      (!string.IsNullOrEmpty(configVersion)) strWhere.Append($" and
      config_version='{configVersion}'"); if (!string.IsNullOrEmpty(ConfigContent))
      strWhere.Append($" and config_content='{ConfigContent}'"); var dt = new
      DataTable();using (SqlConnection con = new SqlConnection("//connectStr//")) {
      var sql = $"select * from dbo.[car_energy_model] where {strWhere.ToString()}";
      using (SqlCommand cmd = new SqlCommand(sql, con)) { // TODO } } } /// <summary>
      /// 靈活查詢 能耗數(shù)據(jù)表 (EFCore) /// </summary> [Route("all")] [HttpGet] public async
      Task<List<CarEnergyModelEntity>> GetModeParametersAsync1( [FromQuery] string
      carVersion, [FromQuery]string carId, [FromQuery] string userId, [FromQuery]
      string soVersion, [FromQuery] string configVersion, [FromQuery] string
      ConfigContent ) {var sqlQuery = _context.CarEnergyModels; if (!string
      .IsNullOrEmpty(carVersion)) sqlQuery = sqlQuery.Where(x=>x.CarVersion ==
      carVersion);if (!string.IsNullOrEmpty(carId)) sqlQuery = sqlQuery.Where(x =>
      x.CarId == carId); if (!string.IsNullOrEmpty(userId)) sqlQuery =
      sqlQuery.Where(x=> x.UserId == userId); if (!string.IsNullOrEmpty(soVersion))
      sqlQUery = sqlQuery.Where(x=> x.SoVersion == soVersion); if (!string
      .IsNullOrEmpty(configVersion)) sqlQuery = sqlQuery.Where(x=> x.ConfigVersion ==
      configVersion);if (!string.IsNullOrEmpty(ConfigContent)) sqlQuery =
      sqlQuery.Where(x=> x.ConfigContent == ConfigContent); return sqlQuery.ToList();
      }
      ? ?特別是在大數(shù)據(jù)產(chǎn)品或者物聯(lián)網(wǎng)產(chǎn)品中,字段甚多; if/else 寫到死,一邊寫一邊吐。

      ? ?寫出優(yōu)雅漂亮的代碼,從移除if/else 開始。

      頭腦風暴

        從靈活查詢的要求看,每一個字段都有為null 或 不為null 的可能, 以上偽代碼6個字段, 理論上最終執(zhí)行查詢時形成的sql 共有2^6=
      64種可能。

      現(xiàn)在我們要寫這么多if 語法,是因為:

      ? -? 在編碼階段,強制判斷字段存在, 并據(jù)此組裝 rawsql

      ? -? 在編碼階段,強制判斷字段存在,并據(jù)此使用lambda強類型 構造IQueryable

      為了解決這個痛點, 引入動態(tài)Linq,動態(tài)Linq的不同之處在于 查詢方法的參數(shù)不限于強類型的lamdba表達式,而是可以使用字符串;

      使用字符串,意味著我們可在運行時動態(tài)決定查詢內(nèi)容
      // 常規(guī)EF Linq: where條件過濾 + 倒排 _context.CarEnergyModels.Where(x=>x.CarVersion ==
      carVersion).OrderByDescending(x=>x.UploadTime); // 動態(tài)EF Linq: where 條件過濾 + 倒排
      _context.CarEnergyModels.Where("carVersion==\"ft_version_3.2\"").OrderBy("
      UploadTime desc");
      ? 同時由于我們在服務端可完全抓取QueryString(可一次性組裝動態(tài)Linq字符串), 故動態(tài)靈活構建查詢的方案呼之欲出。

      編碼實踐

      以上面?zhèn)未a業(yè)務舉例, 根據(jù)條件靈活查詢。

      1.? nuget引入DynamicLinq:
      Install-Package Microsoft.EntityFrameworkCore.DynamicLinq -Version 1.0.19
      2. 定義EFCore 查詢實體類:
      public class CarModelContext : DbContext { public DbSet<CarEnergyModelEntity>
      CarEnergyModels {get; set; } public
      CarModelContext(DbContextOptions<CarModelContext> options) :base(options) { } }
      [Table("car_energy_model")] public class CarEnergyModelEntity { public
      CarEnergyModelEntity() { } [JsonIgnore] [Key]public Guid Id { get; set; }
      [Column("car_version")] public string CarVersion { get; set; } [Column("car_id"
      )]public string CarId { get; set; } [Column("user_id")] public string UserId {
      get; set; } [Column("so_version")] public string SoVersion { get; set; }
      [Column("config_version")] public string ConfigVersion { get; set; } [Column("
      config_content")] public string ConfigContent { get; set; } [Column("uploadtime"
      )]public DateTime UploadTime => DateTime.UtcNow; }
      3. Query集合抓取所有QueryString,列舉字段的方式 判斷字段為null, 并構造查詢
      [Route("all")] [HttpGet] public async Task<List<CarEnergyModelEntity>>
      GetModeParametersAsync( [FromQuery]string carVersion, [FromQuery] string carId,
      [FromQuery]string userId, [FromQuery] string soVersion, [FromQuery] string
      configVersion, [FromQuery]string configContent ) { // 這里使用列舉字段的方式構造 strWhere var
      query = HttpContext.Request.Query; var validQueryArray1 = query.Where(x => (new
      string[] { "CarVersion", "carId", "userId", "soVersion", "configVersion", "
      configContent" }).Contains(x.Key, StringComparer.OrdinalIgnoreCase)) .Where(x
      => !string.IsNullOrEmpty(x.Value)) .Select(x => x.Key + "==\"" + x.Value + "\""
      ).ToArray();string strWhere = string.Join(" and ", validQueryArray1); strWhere =
      string.IsNullOrEmpty(strWhere) ? " 1=1" : strWhere; var sqlQuery =
      _context.CarEnergyModels.Where(strWhere);return sqlQuery.ToList(); }


      ?EFCore生成的SQL如下:
      SELECT [c].[Id], [c].[car_id], [c].[car_version], [c].[config_content], [c].[
      config_version], [c].[so_version], [c].[user_id] FROM [car_energy_model] AS [c]
      WHERE (((([c].[car_version] = N'FT_Version_3.2') AND ([c].[car_id] = N'
      CD292FE0900X')) AND ([c].[user_id] = N'u_1960988792x')) AND ([c].[so_version] =
      N'so_ver1.2')) AND ([c].[config_version] = N'cv_1.2')
      ok, That‘s all?

      移除惡心的 if、else之后代碼是不是看起來更優(yōu)雅一些。

      總結

      以上場景相信很多開發(fā)者都會遇到,特別是進階到一定水平,移除if/else? 的欲望愈加強烈。

      再次強化本文 知識點:? ?

        DynamicLinq 具備動態(tài)形成查詢條件的能力,不再依靠lambda 強類型表達式,而是根據(jù)構造的查詢字符串,內(nèi)部解析成查詢條件。

      ?

      --------------------2019/9/23 下班前更新--------------------------------------

      DynamicLinq? 若動態(tài)組裝String,確實存在 SQL注入問題, 使用placeholder 可避免
      <https://stackoverflow.com/questions/8738953/is-injection-possible-through-dynamic-linq>
      。

      更新代碼:
      // 構建動態(tài)查詢 var query = HttpContext.Request.Query; var validQueryArray1 = query.
      Where(x => (new string[] { "CarVersion", "carId", "userId", "soVersion",
      "configVersion", "configContent" }).Contains(x.Key,
      StringComparer.OrdinalIgnoreCase)) .Where(x => !string.IsNullOrEmpty(x.Value));
      var predicate = validQueryArray1.Select((x,i) => $"{x.Key}==@{i}").ToArray();
      var paramses = validQueryArray1.Select(x=>x.Value.ToString()).ToArray(); string
      strPredicate= string.Join(" and ", predicate); strPredicate =
      string.IsNullOrEmpty(strPredicate) ? "1=1" : strPredicate; var sqlQuery =
      _context.CarEnergyModels.Where(strPredicate, paramses); return
      sqlQuery.ToList();
      ?

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點信息
      問題反饋
      郵箱:[email protected]
      QQ群:637538335
      關注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          com.草逼 | 中文字幕人妻一区二区三区高清 | 亚洲日韩中文在线 | 少妇饥渴偷公乱第28章 | 欧洲裸体片 | 我被下药做得好爽 | 美女高潮喷水影院 | 小茄的性荡生活 | 日本美女日逼视频 | 男生的小鸡鸡插入女生的小鸡鸡 |