说说查询数据表或视图表的3种实现方式C#EF

怎么舒服的写一串 查询数据表的中间代码


最近又喜欢起不那么繁琐的设计,从简单三层的sql开始

基础的类:

    public static class RepositoryBaseExtensions { 
        public static IQueryable<T>WhereIf<T>(this IQueryable<T> qable, bool bf,Expression<Func<T, bool>> whereLambda)
        {
            if (bf) return qable.Where(whereLambda);
            return qable;
        }


        public static string AndStr(this string where1, Func<string> getWhere2, bool condition = true)
        {
            if (condition) return where1 + " and " + getWhere2();
            return where1;
        }
    }


    public class MssqlParter
    {
        static string _safe(object value)
        {
            if (value == null) return "";
            return value.ToString().Replace("'", "''");
        }
        public static string SafeStr(object value)
        {
            if (value == null) return "''";
            if (value is DateTime) { return "'" + ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss").Replace("'", "''") + "'"; }
            if (value is DateTime?) { return "'" + ((DateTime?)value)?.ToString("yyyy-MM-dd HH:mm:ss").Replace("'", "''") + "'"; }
            return "'" + value.ToString().Replace("'", "''") + "'";
        }
        public static string SafeContainStr(object value)
        {
            if (value == null) return "'%'";
            return "'%" + value.ToString().Replace("'", "''") + "%'";
        }
        public static string SafeInStr(IEnumerable<object> arr)
        {
            if (arr == null) return "()";
            return "('" + string.Join("','", arr.Select(x => _safe(x))) + "')";
        }
        public static string SafeInNum(IEnumerable<object> arr)
        {
            if (arr == null) return "()";
            return "(" + string.Join(",", arr.Select(x => _safe(x))) + ")";
        }
        //p_field
        static int MulAnyi = 0;
        public static string MulAny(string[] values, string p_field)
        {
            if (string.IsNullOrEmpty(p_field)) throw new Exception("此过滤 p_field 不可为空");
            if (!p_field.Contains(".")) throw new Exception("此过滤 p_field 未有引用");
            if (values == null) throw new Exception("此过滤 values 不可为空");
            if (!values.Any()) throw new Exception("此过滤 values 不可为空项");
            var s_uinon = "select " + string.Join(" union all select ", values.Select(x => "'[" + x + "]' name0"));
            MulAnyi++;
            return "exists(select 1 from( " + s_uinon + ")auto" + MulAnyi
                + " where len(replace(replace('[' + " + p_field + " + ']',',',']['),name0,''))< len(replace('[' + " + p_field + " + ']', ',', '][')) )";
        }
    }


1。实现一

定义模型:
    public class V_List1_Result
    {
        public Guid ID { get; set; }
        public DateTime? Time1 { get; set; }
        public string Name { get; set; }
    }


query:
    public string query1_Sql(string Name=null,int?ID=null,int[]IDS=null,string FullName =null)
    {
        return "select * from V_List1 where 1=1 "
    .AndStr(()=>"Name like "+MssqlParter.SafeContainStr(Name), !string.IsNullOrEmpty(Name))
    .AndStr(()=>"Name = "+MssqlParter.SafeStr(FullName), !string.IsNullOrEmpty(FullName))
    .AndStr(()=>"ID="+ID, ID!=null)
    .AndStr(()=>"ID in"+MssqlParter.SafeInNum(IDS.Select(d=>d as object))), IDS!=null && IDS.Any())
;
    }


调用者用
var sql=query1_Sql(条件1,条件2。。。)
Database.SqlQuery<V_List1_Result>(sql).ToList()
去序列化出对象来,返回结果


如果需要分页,可以自行封装 //如sqlserver 2012 开始支持 offset fetch next 的,
select *  from(" + sql + ")srctab order by " + orderby + " offset " + (pageSize * (page - 1)) + " rows fetch next " + pageSize + " rows only "



关于注入:
    写sql 主要担心注入的问题,本人所知道的注入,似乎只有1种,即单引号方式,
比如   select   * from table1    where ID=@ID
如果   @ID 的值 是 数字,如 1-999999  等,这种sql 没有可能异常(这种要建立在它是数字的基础上)
如果   @ID 是字符串,如  'abcd'   ,为正常,如   'abcd'' 则为异常,因为多了单引号
  以此扩展为:   输入   'abde' ; delete from table1 ,这种,可能性也不高,一般是采用   因为 一般会人为的在外层加上 '' ,它就变成  ''abde' ; delete from table1'  报错, 
所有大家都想到了,如果输入  ';delete from table where Name!='     则它经过一般外层加上'' ,就会变成   '';delete from table where Name!=''    ,注意前面的 ''  是上个sql查询的条件,它执行完,就执行了delete ,就悲剧了,
  所以个人觉得一般是单引号引起的,不知道有没有说错,
  所索性c#就把输入参数 replace("'","''")  或者  replace("'","")  不就好了
 

2。关于 iqueryable<T>   //条件 condition
    一般orm如ef的 dbset<T>() .  WhereIf(condition, x=>x.ID== Query_ID).
 .  WhereIf(condition, x=>x.ID== Query_ID)

它适合orm转换都较完善,且需求不那么个性化,
如有的报表关联复杂,且调整可能性较大,且一改若都是大改,那可能还不如写sql开心了


为什么不用 iqueryable<ef的视图模型>
ef的视图alter 以后的视图的字段类型就被记录,从db到ef后,如果db再修改了类型,则ef的query 可能就会报错,如一个字段,从 int 变成了 int? 可空的int,然后数据出收了 null ,这里没有更新ef模型,它即会报错
而在自定义模型则可以直接使用 int?
当然,如果ef视图随时都是全部更新的,一般也不会有这个问题,怕的是数据库和ef的类型有不一致的 3. 提前存储了所有字段的表信息,存成一个 key ,拿这个key ,和条件参数,得到一个表,(一个dataTable,因为这里没有定义模型表) 这种方式是减少了结果模型的定义,且它的参数,可以直接在存储的地方(如数据库)直接的变更 不好的地方, a1.可能就是配置的操作比较繁琐,比如它要定义 结果列, a2.另外,如果它如果需要代码里操作,可能又想定义一个模型类, a3.假如需要两个并集,如 v1 union all v2 而使用 第1的方式,它可以 v1(where condition) union all v2(where condition) 而第3方式,只能 ( v1 union all v2 ) (where condition) // -- -- --如有引用,注名出处,谢谢

  

posted @ 2023-11-24 15:31  以函  阅读(19)  评论(0编辑  收藏  举报