企业管理软件开发架构之七 Object Control设计与运用

在做查询时,经常遇到一类需求。请看下面的SQL语句查询

SELECT * FROM Company
WHERE CompanyCode='Kingston' AND Suspended='N' AND DbServer='James\SQLEXPRESS'
 

这里有三个条件,在界面中,也就是我们需要增加三个控件来供用户输入值,再拼接成SQL发送到服务器。

再来看一下界面中的情况,根据客户名称,下单日期,是否过帐,是否完成4个选项来读取发票信息

image

点击Refresh按钮之后,产生的SQL条件,可能像下面这样写的一样

SELECT  *  FROM Invoce WHERE  Customer='A'  and IssueDate='2013-06-16' and  Posted='Y' and Closed='N'
 

现在遇到的问题时,读取界面中的控件的用户输入值,转化为SQL条件,需要经历一些复杂的重复的操作。

如果用户在这四个控件不输入任何值,那么生成的SQL语句应该直接是

SELECT  *  FROM Invoce

如果用户只想通过发票日期来过滤,则SQL语句应该是这样的

SELECT  *  FROM Invoce WHERE IssueDate='2013-06-16'

或者是其它的情况,因为WHERE部分的条件出现的时机不确定,所以我们产生的SQL通常是这样的,在考虑全部情况

SELECT  *  FROM Invoce WHERE 1=1 
AND   Customer='A'  and IssueDate='2013-06-16' and  Posted='Y' and Closed='N'
 
 

为了解决这一类问题,下面解释一下,我所遇到到的最好的办法。

设计object control,如下图中所示。添加EntityName和FieldName

image

在运行时,以下面的代码获取它产生的SQL语句条件

efcCustomerNo.GetPredicateExpression();
 

这样设计方法,考虑了以下几种情况

1  当用户不在控件中输入任何值时,上面的原代码不返回任何条件。

2 用户想输入一个范围内的值,输入两个值之后,产生 BETWEEN A AND B条件

3 用户想输入一个唯一的过滤条件值,输入一个值A,产生条件 CustomerNo=’A’

依据查询的可能,还有可能是like,模糊查询。请看下面的枚举值

public enum ReportFieldSelectionCondition
    {
        [DisplayText("All")]
        All = 0,
        [DisplayText("Equal")]
        Equal = 1,
        [DisplayText("Exclude")]
        Exclude = 6,
        [DisplayText("Include")]
        Include = 5,
        [DisplayText("In Range")]
        InRange = 3,
        [DisplayText("Like")]
        Like = 7,
        [DisplayText("Not Equal")]
        NotEqual = 2,
        [DisplayText("Not Like")]
        NotLike = 8,
        [DisplayText("Out Range")]
        OutRange = 4
    }

查询条件的几种情况,它都考虑到。根据这些情况,产生不同的SQL条件部分,供程序调用。

控件的基础代码稍微有些复杂,以Between为例子,代码像这样所示

if (!flag)
 {
             expression.Add((IPredicate) (field >= valueFrom));
 }
if (!flag2)
 {
             expression.Add((IPredicate) (field <= valueTo));
 }

代码的意图明了,第一个控件中有值时,产生<=的表达式,第二个控件中有值时,产生>=的条件。

有三种类型的object control,字符串类型,日期类型和bool类型,上面的图中有全部显示。

字符串类型经常遇到,这篇文章中解释了这个类型的控件,日期类型与字符串相似,产生的条件是日期的比较操作。

bool类型是为了解决一些值,真/假的情况。比如是否过帐,日记帐是否完成。控件有二个基本的属性

   [DefaultValue(""), EditorBrowsable(EditorBrowsableState.Always),  Browsable(true)]
        public string EntityName
        {
            get
            {
                return this._entityName;
            }
            set
            {
                this._entityName = value;
            }
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue("")]
        public string FieldName
        {
            get
            {
                return this._fieldName;
            }
            set
            {
                this._fieldName = value;
            }
        }

如果接触过ORM的查询的写法,可能有很多代码像下面这样

 if (!AllowViewAllTransaction)
                args.PredicateBucket.PredicateExpression.Add(AccountsReceivableInvoiceFields.CreatedBy == Shared.CurrentUser.Userid);

            if (!Shared.CurrentUserSession.AllowAccessAllCustomers)
                args.PredicateBucket.PredicateExpression.Add(Shared.GetAllowedCustomerNoPredicateExpression(AccountsReceivableInvoiceFields.CustomerNo));

            if (_show)
            {
                _peCustomerNo = this.efcCustomerNo.GetPredicateExpression();
                _pePostedFilter = this.efcPostedFilter.GetPredicateExpression();
                _peIssueDate = this.efcIssueDate.GetPredicateExpression();
                _peClosedFilter = this.efcClosedFilter.GetPredicateExpression();

                FetchAccountsReceivableInvoice();
            }

PredicationExpress类型相当于 CustomerNo=’A’ 这样的条件的面向对象的封装,最终产生的SQL条件,与开头的一样,这个过程由ORM框架来负责产生,根据类型及其属性,产生对应的SQL语句。

如果没有应用ORM工具,缺少entityName和fieldName,同样也可以应用这里介绍的技术,直接用SQL表名和字段名即可,再根据各种条件组合判断,产生不同的查询条件。

应用本文中的方法,在做查询类程序时,可以节省大量的重复的代码。

posted @ 2013-06-22 08:45  信息化建设  阅读(1884)  评论(1编辑  收藏  举报