首页 新闻 会员 周边

.net4年,对数据访问层接口设计的思考和疑问

0
悬赏园豆:10 [已解决问题] 解决于 2017-08-02 11:01

方式1:使用条件拼接的方式,有业务逻辑层传入拼接好的where条件

优点:通用性强,灵活。业务逻辑层很多的查询方法可以只调用dal的一个方法就行了

缺点:不面向对象,容易写错,容易出现sql注入问题、不能更换dal层,应为你按sqlserver的语法拼接where条件写在业务逻辑层,我换个mysql呢?

 

方式2:原始方式,在DAL中根据业务逻辑需要定义相应的查询

优点:在没有其它方案的时候比较倾向这种方式,因为dal层应该为bll层提供直观,简单的接口

缺点:通用性差,dal的类中可以出现很多重载,有需求变化是又要添加重载或添加、修改方法,代码量太多了

 

方式3:查询对象模式

优点:在不了解ORM之前,我认为这是最好的方式。BLL根据业务需要去创建查询对象,不同的DAL实现自己将这个查询对象解析成符合自己语法的sql条件语句。面向对象的方式

缺点:如果考虑某天DAL使用EF呢?那么需要将我们自己定义的查询对象再翻译成表达式树Expression,这玩意真心有点复杂,

 

方式4:自己实现IQueryProvider

个人感觉最好,最难的方式

变形精怪的主页 变形精怪 | 初学一级 | 园豆:5
提问于:2017-08-02 09:37
< >
分享
最佳答案
0

EF没那么好用的. 我到现在都只在自己给别人做的项目里正经用了一下.

还是自己写的dal层好用.

收获园豆:10
吴瑞祥 | 高人七级 |园豆:29449 | 2017-08-02 09:47

你的数据访问层DAL的查询方法怎么定义的? 让BLL传过来拼接好的条件,还是为不同的查询定义不同的方法,还是别的方式?

变形精怪 | 园豆:5 (初学一级) | 2017-08-02 09:50

@jionsoft: dal层都是自动生成的.具体用法是

db.表名.查询(m=>条件表达式) 这样

或者 db.表名.操作(new{新值},条件)

吴瑞祥 | 园豆:29449 (高人七级) | 2017-08-02 09:51

@吴瑞祥: 方便加个Q 截图我看看吗? 我的453008453

变形精怪 | 园豆:5 (初学一级) | 2017-08-02 09:53

@jionsoft: 

吴瑞祥 | 园豆:29449 (高人七级) | 2017-08-02 09:56

@吴瑞祥: 对啊,就想要这样的。这什么思路,用起来跟ef一样简单, 我说的方式4? 这不是用的ef吗?

变形精怪 | 园豆:5 (初学一级) | 2017-08-02 10:00

@jionsoft: ef不是这样的.如果这种用法还不如别用ef.

ef的关键是对象关系映射.而不是对象表映射.一般人的用法都是在很表面的对象表映射.

我这个是直接封装了ormlite.虽然这些工具都叫orm.但其实都是表对象映射.

关系是关系不了的.

吴瑞祥 | 园豆:29449 (高人七级) | 2017-08-02 10:03

@吴瑞祥: 有点不太多,做.net也快5年了,这问题一直没搞太懂。一般接私活什么的,我直接用的EF,而且是强依赖,没有定义DAL层,BLL里直接用的DBContext。现在在做的项目用的简单三层,DAL用的Dapper,DAL里面类用定义的  完全是考虑BLL需要什么就定义什么, 参数也是根据BLL需要定义的,主要是类似仓储模式,BLL要什么就提供什么,问题是DAL会定义很多查询重载。

变形精怪 | 园豆:5 (初学一级) | 2017-08-02 10:18

@jionsoft: 用ef的话就是直接用.不用封装的.我不用ef的问题在于他的并发处理实在是太麻烦了..

dal不用写查询重载的.我的dal层提供几个方法.

 /// <summary>
    /// 命令基类.实现数据库操作
    /// </summary>
    /// <typeparam name="T">要操作的表实体</typeparam> 
    public class CommandBase<T> : QueryBase<T> where T : YW.Model.HasId
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="db"></param>
        public CommandBase(string db) : base(db) { }

        /// <summary> 插入一个实体
        /// </summary>
        /// <param name="entity">要插入的实体</param>
        /// <returns>受影响的行数</returns>
        public long Insert(T entity)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                entity.Id = conn.Insert(entity, true);
                return entity.Id;
            }
        }

        /// <summary> 插入一个实体数组
        /// </summary>
        /// <param name="entitys">要插入的实体数组</param>
        /// <returns>受影响的行数</returns>
        public int Insert(IEnumerable<T> entitys)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                if (DbSession.InDbTrasaction)
                {
                    foreach (var entity in entitys)
                    {
                        entity.Id = conn.Insert(entity, true);
                    }
                }
                else
                {
                    using (var dt = conn.BeginTransaction())
                    {
                        foreach (var entity in entitys)
                        {
                            entity.Id = conn.Insert(entity, true);
                        }
                        dt.Commit();
                    }
                }
            }
            return entitys.Count();
        }

        /// <summary> 删除一个实体
        /// </summary>
        /// <param name="id">要删除的实体id</param>
        /// <returns>受影响的行数</returns>
        public int Delete(long id)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.DeleteById<T>(id);
            }
        }

        /// <summary> 删除一个实体数组
        /// </summary>
        /// <param name="ids">要删除的实体id数组</param>
        /// <returns>受影响的行数</returns>
        public int Delete(IEnumerable<long> ids)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.DeleteByIds<T>(ids);
            }
        }

        /// <summary> 根据条件删除
        /// </summary>
        /// <param name="predicate">删除的条件表达式</param>
        /// <returns>受影响的行数</returns>
        public int Delete(Expression<Func<T, bool>> predicate)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.Delete(predicate);
            }
        }

        /// <summary>
        /// 根据id更新一个实体
        /// </summary>
        /// <param name="entity">要更新的实体.</param>
        /// <returns>受影响的行数</returns>
        public int Update(T entity)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.Update(entity);
            }
        }


        /// <summary>
        /// 根据id更新一个实体数组
        /// </summary>
        /// <param name="entitys">要更新的实体数组.</param>
        /// <returns>受影响的行数</returns>
        public int Update(IEnumerable<T> entitys)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                if (DbSession.InDbTrasaction)
                {
                    foreach (var item in entitys)
                    {
                        conn.Update(item);
                    }
                }
                else
                {
                    using (var dt = conn.BeginTransaction())
                    {
                        foreach (var item in entitys)
                        {
                            conn.Update(item);
                        }
                        dt.Commit();
                    }
                }
            }
            return entitys.Count();
        }


        /// <summary>
        /// 根据条件更新部分字段
        /// </summary>
        /// <param name="fields"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public int Update(object fields, Expression<Func<T, bool>> predicate)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.Update(fields, predicate);
            }
        }
        /// <summary>
        /// 增量更新方法
        /// 例子:UpdateAdd(()=>new T{Field=1(或者-1)},m=>条件表示)
        /// </summary>
        /// <param name="updateFields">要修改的字段和增量值,不修改的字段不赋值</param>
        /// <param name="where">条件表达式</param>
        /// <returns></returns>
        public int UpdateAdd(Expression<Func<T>> updateFields, Expression<Func<T, bool>> where = null)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.UpdateAdd(updateFields, where);
            }
        }

    }
    public class QueryBase<T> where T : YW.Model.HasId
    {
        protected string DbName;
        public QueryBase(string db)
        {
            DbName = db;
        }

        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns></returns>
        public IEnumerable<T> SelectAll()
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.Select<T>();
            }
        }

        public T Single(long id)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.SingleById<T>(id);
            }
        }

        public T Single(Expression<Func<T, bool>> predicate)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.Single(predicate);
            }
        }

        public T Single(Action<SqlExp<T>> expression)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                var exp = SqlExp<T>.GetSqlExp(conn);
                expression(exp);
                return conn.Single(exp.GetExp());
            }
        }

        public IEnumerable<T> Where(IEnumerable<long> ids)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.SelectByIds<T>(ids);
            }
        }

        public IEnumerable<T> Where(Expression<Func<T, bool>> predicate)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                var result = conn.Select(predicate);
                return result;
            }
        }

        public IEnumerable<T> Where(Action<SqlExp<T>> expression)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                var exp = SqlExp<T>.GetSqlExp(conn);
                expression(exp);
                var r = conn.Select(exp.GetExp());
                var sql = conn.GetLastSql();
                sql += "";
                return r;
            }
        }

        public int Count(Expression<Func<T, bool>> predicate)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return (int)conn.Count(predicate);
            }
        }

        public int Count(Action<SqlExp<T>> expression)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                var exp = SqlExp<T>.GetSqlExp(conn);
                expression(exp);
                return (int)conn.Count<T>(exp.GetExp());
            }
        }

        public bool Any(Expression<Func<T, bool>> predicate)
        {
            return (Count(predicate) > 0);
        }

        public PagedResultModel<T> QueryPage(
            Expression<Func<T, bool>> where,
            Expression<Func<T, object>> orderByKeySelector = null,
            bool isDesc = false,
            int pageIndex = 1,
            int pageSize = 20)
        {
            var result = new PagedResultModel<T>
            {
                Page = pageIndex,
                PageSize = pageSize,
                RowCount = Count(where),
                Body = Where(m =>
                {
                    m.And(where);
                    if (orderByKeySelector != null)
                    {
                        if (isDesc)
                        {
                            m.OrderByDescending(orderByKeySelector);
                        }
                        else
                        {
                            m.OrderBy(orderByKeySelector);
                        }
                    }
                    m.Limit((pageIndex - 1) * pageSize, pageSize);
                })
            };
            return result;
        }

        public PagedResultModel<T> QueryPage(
            Action<SqlExp<T>> expression,
            Expression<Func<T, object>> orderByKeySelector = null,
            bool isDesc = false,
            int pageIndex = 1,
            int pageSize = 20)
        {
            var result = new PagedResultModel<T>
            {
                Page = pageIndex,
                PageSize = pageSize,
                RowCount = Count(expression),
                Body = Where(m =>
                {
                    expression(m);
                    if (orderByKeySelector != null)
                    {
                        if (isDesc)
                        {
                            m.OrderByDescending(orderByKeySelector);
                        }
                        else
                        {
                            m.OrderBy(orderByKeySelector);
                        }
                    }
                    m.Limit((pageIndex - 1) * pageSize, pageSize);
                })
            };
            return result;
        }

        public TKey Sum<TKey>(Expression<Func<T, object>> field, Expression<Func<T, bool>> predicate)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                var exp = conn.GetDialectProvider().SqlExpression<T>();
                exp.Select(Sql.Sum(exp.ModelDef.GetFieldDefinition(field).FieldName));
                exp.And(predicate);
                var result = conn.Scalar<TKey>(exp);
                return result;
            }
        }

    }
吴瑞祥 | 园豆:29449 (高人七级) | 2017-08-02 10:42

@吴瑞祥: 其实我就是想要你这种方式,不依赖EF,又跟EF一样简单的语法

public int Delete(Expression<Func<T, bool>> predicate)
        {
            using (var conn = DbConnFactory.Open(DbName))
            {
                return conn.Delete(predicate);
            }
        }
predicate这个参数是怎么转换成最终sql条件语句的,用的什么框架还是自己解析表达式树?

对EF并发我不太了解,包括数据库并发。不过我觉得EF都到6了,微软也花这么多力气。 用起来真心挺省事。建议还是再花点时间找找EF并发的解决办法。 没有特殊要求其实EF开发起来很省事。我一般会选用EF,但是不想项目依赖它



变形精怪 | 园豆:5 (初学一级) | 2017-08-02 10:51

@jionsoft: 我这个是封装了ORMLITE的.

ef是好.并且并发也有解决方案.但是不好用.

吴瑞祥 | 园豆:29449 (高人七级) | 2017-08-02 10:52

@吴瑞祥: 朋友~ 感谢哈。非常感谢~

变形精怪 | 园豆:5 (初学一级) | 2017-08-02 11:01

@jionsoft: 我觉得这样虽然麻烦,那比较好容易更换DAL阿

sammy123 | 园豆:174 (初学一级) | 2019-08-20 20:22
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册