【问题标题】:How do you write a parameterized where-in raw sql query in Entity Framework如何在实体框架中编写参数化的 where-in 原始 sql 查询
【发布时间】:2014-08-26 00:41:16
【问题描述】:

如何在实体框架中编写参数化的 where-in 原始 sql 查询?我尝试了以下方法:

string dateQueryString = String.Join(",", chartModelData.GetFormattedDateList());
//Dates returned in format of 20140402,20140506,20140704

const string selectQuery = 
    @"SELECT 
         MAX(DATA_SEQ) AS MaxSeq, MIN(DATA_SEQ) AS MinSeq, COUNT(1) AS TotSampleCnt
      FROM SPCDATA_TB
      WHERE DATA_WDATE IN @DateParam  
      AND LINE_CODE = @LineCode
      AND MODEL_NO = @ModelNumber
      AND LOT_NO = @LotNumber
      AND EQUIP_NO LIKE @EquipNumber";

SPCDataSeqCntInfo dataSeqCntInfo = _dbContext.Database.SqlQuery<SPCDataSeqCntInfo>(
      selectQuery,
      new SqlParameter("@DateParam",   dateQueryString),
      new SqlParameter("@LineCode",    chartModelData.LineCode),
      new SqlParameter("@ModelNumber", chartModelData.ModelNum),
      new SqlParameter("@EquipNumber", equipmentNumber),
      new SqlParameter("@LotNumber",   chartModelData.LotNum)
  ).SingleOrDefault() ?? new SPCDataSeqCntInfo();

但正如预期的那样,它会在 DateParam 上引发错误,因为它需要一个值。

【问题讨论】:

  • @DateParam 应该是一个逗号分隔的字符串,表示您希望在集合中查找的日期,然后它也应该用括号分隔。

标签: c# sql .net asp.net-mvc entity-framework


【解决方案1】:

这不是实体框架特有的问题,您可以通过动态生成自己的参数名称来解决它。

var parameters = new List<SqlParameter> {
    new SqlParameter("@DateParam", dateQueryString),
    new SqlParameter("@LineCode", chartModelData.LineCode),
    new SqlParameter("@ModelNumber", chartModelData.ModelNum),
    new SqlParameter("@EquipNumber", equipmentNumber),
    new SqlParameter("@LotNumber", chartModelData.LotNum)   
};

var dateParameters = chartModelData
    .GetFormattedDateList()
    .Select((date, index) => new SqlParameter("@date" + index, date));
    .ToList();

parameters.AddRange(dateParameters);
    
var inValues = string.Join(", ", dateParameters.Select(p => p.ParameterName));

var query = @"SELECT MAX(DATA_SEQ) AS MaxSeq, 
   MIN(DATA_SEQ) AS MinSeq, 
   COUNT(1) AS TotSampleCnt
   FROM SPCDATA_TB
   WHERE DATA_WDATE IN (" + inValues + @")  
   AND LINE_CODE = @LineCode
   AND MODEL_NO = @ModelNumber
   AND LOT_NO = @LotNumber
   AND EQUIP_NO LIKE @EquipNumber";

var myResult = _dbContext.Database
    .SqlQuery<SPCDataSeqCntInfo>(query, parameters.ToArray());

发送到 SQL-Server 的查询结果如下所示:

SELECT 
   MAX(DATA_SEQ) AS MaxSeq, 
   MIN(DATA_SEQ) AS MinSeq, 
   COUNT(1) AS TotSampleCnt
FROM SPCDATA_TB
WHERE DATA_WDATE IN (@date0, @date1, @date2)  
AND LINE_CODE = @LineCode
AND MODEL_NO = @ModelNumber
AND LOT_NO = @LotNumber
AND EQUIP_NO LIKE @EquipNumber

通常,您希望在编写查询时避免进行字符串操作,但是,我相信这个示例可以避免 sql-injection。

【讨论】:

    【解决方案2】:

    以下是您在 SQL 中编写查询的方式。

    select *
        from MyTable
        where dateColumn in ('2014-01-01', '2014-02-01', '2014-03-01')
    

    因此,除了必须用括号完全分隔这个字符串之外,别无所求。

    var dateQueryString = string.Join(",", chartModelData.GetFormattedDateList());
    // Dates shall be returned as DateTime.ToShortDateTimeString() as follows:
    // '2014-01-01', '2014-02-01', '2014-03-01'
    

    那么只剩下用括号括起来了。

    var sql = @"select max(data_seq)    as MaxSeq
                        , min(data_seq) as MinSeq
                        , count(1)      as TotSampleCnt
                    from spcdata_tb
                    where data_wadate in (@DateParam)
                        and line_code  =  @LineCode
                        and model_no   =  @ModelNumber
                        and lot_no     =  @LotNumber
                        and equip_no like @EquipNumber";
    

    为每个命名参数提供参数值,瞧!这样就可以了!

    【讨论】:

      【解决方案3】:

      我会编写一个存储过程来接受您的参数,然后将该过程添加到您的 edmx。

      然后,在 edmx -> Model Browser -> Function Imports -> ... 将存储过程的返回类型更改为 SPCDataSeqCntInfo。

      然后,实体框架将负责传递您的参数。

      例如

      public static List<SPCDataSeqCntInfo> GetSPCDataSeqCntInfo(DateTime dateParam, string lineCode, int modelNum, int equipmentNumber, int lotNum)
      {
          using (var db = new NameOfMyEntites())
          {
              return db.sp_GetSPCDataSeqCntInfo(dateParam, lineCode, modelNum, equipmentNumber, lotNum).ToList();
          }
      }
      

      【讨论】:

      • 好的。我想这是一个公平的选择,但是如果不诉诸存储过程,就绝对没有办法完成我想做的事情吗?只是为了好奇。
      • 看看使用 _dbContext.Database.ExecuteSqlCommand 代替。
      猜你喜欢
      • 2013-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多