MyORM的使用(二)

 

 SimpleCondition与ConditionSet

查询是最常用的数据库操作,最普通的查询条件一般是某个字段满足某个条件,这类查询可能超过了一半。

因此MyOrm里定义了SimpleCondition和ConditionSet两个Condition类型。SimpleCondition的定义非常简单:名称、用于比较的操作符、值。为操作符定义了ConditionOperator的枚举,定义为:

  1.     /// <summary>
  2.     /// 条件判断操作符
  3.     /// </summary>
  4.     public enum ConditionOperator
  5.     {
  6.         /// <summary>
  7.         /// 相等
  8.         /// </summary>
  9.         Equals = 0,
  10.         /// <summary>
  11.         /// 大于
  12.         /// </summary>
  13.         LargerThan = 1,
  14.         /// <summary>
  15.         /// 小于
  16.         /// </summary>
  17.         SmallerThan = 2,
  18.         /// <summary>
  19.         /// 以指定字符串为开始(作为字符串比较)
  20.         /// </summary>
  21.         StartsWith = 3,
  22.         /// <summary>
  23.         /// 以指定字符串为结尾(作为字符串比较)
  24.         /// </summary>
  25.         EndsWith = 4,
  26.         /// <summary>
  27.         /// 包含制定字符串(作为字符串比较)
  28.         /// </summary>
  29.         Contains = 5,
  30.         /// <summary>
  31.         /// 逻辑否(非判断操作符)
  32.         /// </summary>
  33.         Not = 0xF000,
  34.         /// <summary>
  35.         /// 不相等
  36.         /// </summary>
  37.         NotEquals = Not | Equals,
  38.         /// <summary>
  39.         /// 小于或等于
  40.         /// </summary>
  41.         NotLargerThan = Not | LargerThan,
  42.         /// <summary>
  43.         /// 大于或等于
  44.         /// </summary>
  45.         NotSmallerThan = Not | SmallerThan,
  46.         /// <summary>
  47.         /// 以指定字符串为开始(作为字符串比较)
  48.         /// </summary>
  49.         NotStartsWith = Not | StartsWith,
  50.         /// <summary>
  51.         /// 以指定字符串为结尾(作为字符串比较)
  52.         /// </summary>
  53.         NotEndsWith = Not | EndsWith,
  54.         /// <summary>
  55.         /// 不包含制定字符串(作为字符串比较)
  56.         /// </summary>
  57.         NotContains = Not | Contains
  58.     }

基本上包括了常用的比较符,定义的比较繁琐,是因为SQL语句里对于Not的表达方式是多种的,为了拼SQL方便。把SimpleCondition解析为SQL,是在ObjectDAOBase的BuildSimpleConditionSql(SimpleCondition simpleCondition, IList outputParams)方法里实现。

ConditionSet是Condition的集合,可以看作是多个Condition的树状结构,另外定义了ConditionJoinType表示通过And或Or连接。

Condition的定义是和数据库无关的,它是一般查询的通用的表达方式。如果有可能,其他类型的查询也可以通过Condition来表示。其实LINQ已经实现了统一的方式,它考虑的更严谨更复杂,但是也并不能完全满足SQL查询的要求。

 

Search方法

然后就是查询的方法了。Search方法的定义很简单:

  1.         public virtual List<T> Search(Condition condition)
  2.         {
  3.             using (IDbCommand command = MakeConditionCommand("select @AllFields from @FromTable where @Condition", condition))
  4.             {
  5.                 return ReadAll(command.ExecuteReader());
  6.             }
  7.         }

 

其中使用了MakeConditionCommand,在MakeConditionCommand的SQLWithParam参数里用"@AllFields","@Table","@FromTable","@Condition"标记分别代表SQL语句里的所有列、表名、多表连接和where条件,而where条件是通过condition参数生成的,至于怎么生成在BuildConditionSql(Condition conditon, IList outputParams)里实现。

了解了MakeConditionCommand之后也可以通过它方便的构造Command,例如

  1.     MakeConditionCommand("select count(*) from @FromTable ",null)

得到的是求所有行数的Command;

  1.     MakeConditionCommand("delete from @Table where @Condition", condition)

得到的是删除所有满足条件的数据的Command。

 

Search的使用

使用也很简单,只需要生成Condition就可以了。

例如需要查询所有CategoryName为Seafood,ProductName中包含"Coffee",UnitPrice大于2.5的ProductsView:

  1.     ConditionSet conditions = new ConditionSet();
  2.     conditions.Add(new SimpleCondition("Category_CategoryName""Seafood"));
  3.     conditions.Add(new SimpleCondition("ProductName",  ConditionOperator.Contains, "Coffee"));
  4.     conditions.Add(new SimpleCondition("UnitPrice",  ConditionOperator.LargerThan,  2.5));
  5.     List<ProductsView> products = new ProductsViewDAO().Search(conditions);

如果ProductName的条件改为:包含"Coffee"或者为空,那么改成这样:

  1.     ConditionSet conditions = new ConditionSet();
  2.     conditions.Add(new SimpleCondition("Category_CategoryName""Seafood"));
  3.     ConditionSet subConditions = new ConditionSet(ConditionJoinType.Or);
  4.     subConditions.Add(new SimpleCondition("ProductName",  ConditionOperator.Contains, "Coffee"));
  5.     subConditions.Add(new SimpleCondition("ProductName"null));
  6.     conditions.Add(subConditions);
  7.     conditions.Add(new SimpleCondition("UnitPrice",  ConditionOperator.LargerThan,  2.5));
  8.     List<ProductsView> products = new ProductsViewDAO().Search(conditions);

稍微繁琐了些,不过比拼字符串的方式要让人放心一些。LINQ之所以能那么简洁是因为编译器的帮助,这方面是比不了了。

 

ProductsDAO和ProductsViewDAO的自定义方法

虽然Search方法可以完成一般的查询,但是免不了有无法完成的查询。建议在继承ObjectDAO<T>和ObjectViewDAO<T>的实体类DAO中通过自定义方法封装查询。例如需要查询订单总额在指定金额以上的ProductsView,定义GetAllWithTotalTurnoverLargerThan方法:

  1.         public List<ProductsView> GetAllWithTotalTurnoverLargerThan(float totalTurnover)
  2.         {
  3.             using (IDbCommand command = MakeParamCommand(String.Format("select {0} from {1} where (select sum({2} * {3}) from {4} where {4}.{5} = {6}.{7}) > {8}",
  4.                 AllFieldsSql,
  5.                 FromTable,
  6.                 ToSqlName(OrderDetails._UnitPrice),
  7.                 ToSqlName(OrderDetails._Quantity),
  8.                 ToSqlName(Configuration.TableInfoProvider.GetTableInfo(typeof(OrderDetails)).TableName),
  9.                 ToSqlName(OrderDetails._ProductID),
  10.                 ToSqlName(TableName),
  11.                 ToSqlName(Products._ProductID),
  12.                 ToSqlParam("0")),
  13.                 new object[] { totalTurnover }))
  14.             {
  15.                 return ReadAll(command.ExecuteReader());
  16.             }
  17.         }

其中OrderDetails._UnitPrice、OrderDetails._Quantity是表示相应属性名的字符串常量。也可以直接用字符串,但是属性名不正确的话在运行时才能发现。

另外还有常用的包含业务逻辑的查询,虽然也是简单的查询,但是最好还是封装为相应的方法。ProductsDAO和ProductsViewDAO的实际定义:

  1.     public class ProductsDAO : ObjectDAO<Products>, IProductsDAO
  2.     {
  3.         public Products GetProductOfOrderDetail(OrderDetails orderDetails)
  4.         {
  5.             return GetObject(orderDetails.ProductID);
  6.         }
  7.         public List<Products> GetAllWithCategory(Categories category)
  8.         {
  9.             return Search(new SimpleCondition(Products._CategoryID, category.CategoryID));
  10.         }        
  11.         public List<Products> GetAllWithSupplier(Suppliers supplier)
  12.         {
  13.             return Search(new SimpleCondition(Products._SupplierID, supplier.SupplierID));
  14.         }
  15.     }
  1. public class ProductsViewDAO : ObjectViewDAO<ProductsView>, IProductsViewDAO
  2.     {
  3.         public ProductsView GetProductOfOrderDetail(OrderDetails orderDetails)
  4.         {
  5.             return GetObject(orderDetails.ProductID);
  6.         }
  7.         public List<ProductsView> GetAllWithCategory(Categories category)
  8.         {
  9.             return Search(new SimpleCondition(ProductsView._CategoryID, category.CategoryID));
  10.         }
  11.         public List<ProductsView> GetAllWithSupplier(Suppliers supplier)
  12.         {
  13.             return Search(new SimpleCondition(ProductsView._SupplierID, supplier.SupplierID));
  14.         }
  15.     }

这样的封装可以满足对于权限、日志等等的要求,因为它反映的是实际业务的需求,而不是纯粹的查询。

 

接下来会介绍一些MyORM结合界面使用的例子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值