在上篇随笔《Entity Framework 实体框架的形成之旅–数据传输模型DTO和实体模型Entity的分离与联合》里面,介绍了在Entity Framework 实体框架里面引入了DTO的对象,通过数据传输模型DTO和实体模型Entity的分离与联合,很好的隔离了它们的关系,使得即使是复杂的实体模型Entity,也不会影响WCF接口数据的传输和处理。本文主要介绍在基于这个分离模型的基础上,如何在界面实现多种常规的处理操作。
对于业务对象的增加,由于我们引入了DTO对象,因此在界面的处理端,肯定也是利用了DTO对象进行的,如下代码是增加、修改的处理操作处理。
public bool SaveAddNew()
{
DictDataInfo info = new DictDataInfo();
SetInfo(info);
try
{
bool succeed = CallerFactory.Instance.Insert(info);
if (succeed)
{
int intSeq = 0;
string seqValue = this.txtSeq.Text;
if (int.TryParse(seqValue, out intSeq))
{
this.txtSeq.Text = (intSeq + 1).ToString().PadLeft(seqValue.Trim().Length, \'0\');
}
this.txtName.Focus();
this.txtName.SelectAll();
}
return succeed;
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
MessageDxUtil.ShowError(ex.Message);
}
return false;
}
public override bool SaveUpdated()
{
DictDataInfo info = CallerFactory.Instance.FindByID(ID);
if (info != null)
{
SetInfo(info);
try
{
bool succeed = CallerFactory.Instance.Update(info, info.ID.ToString());
return succeed;
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
MessageDxUtil.ShowError(ex.Message);
}
}
return false;
}
上面的操作,和我之前的混合框架的使用代码是差不多的,原来的基于EnterpriseLibrary架构的框架,实体类采用的就是 \”表名+Info\” 的方式,虽然这里的**Info代表DTO对象,是实体框架的Entity对象的映射类,不过总体业务上的处理代码是差不多的了,这也是我希望看到比较平滑过渡和容易理解的改变之一。
如果对于查询,我们知道,如果使用字符串的条件表达式,一般也是可以实现处理操作的,不过就是需要硬编码SQL语句,对于一些安全性高一点的处理,可能不太好,由于实体框架可以采用Lamda表达式来进行查询,那么我们是否也可以在界面采用Lamda表达式来替代条件的SQL语句呢?
我们知道,上篇随笔已经介绍了引入DTO对象,用来解耦实体框架的对象模型,如下所示的模块分层场景。
这样我们在设计BLL业务逻辑层的时候,肯定还是可以使用实体框架的Expression
///
/// 根据条件查询数据库,并返回对象集合
///
/// 条件表达式
///
IList Find(Expression> match);
///
/// 根据条件表达式返回可查询的记录源
///
/// 查询条件
/// 排序属性名称
/// 如果为true则为降序,否则为升序
///
IQueryable GetQueryable(Expression> match, string sortPropertyName, bool isDescending = true);
不过在门面层Facade层就不能继续使用了这种Expression
那基于这个原因,我们应该如何传递Expression
///
/// 根据条件查询数据库,并返回对象集合
///
/// 条件表达式
///
[OperationContract(Name = \"Find\")]
IList Find(ExpressionNode match);
///
/// 根据条件查询数据库,并返回对象集合(异步)
///
/// 条件表达式
///
[OperationContract(Name = \"FindAsync\")]
Task> FindAsync(ExpressionNode match);
我们在客户端界面里面处理的话,就需要构建一个ExpressionNode对象,查询处理代码如下所示。
这里主要需要先从Expression
private ExpressionNode GetCondtionSql()
{
Expression> expression = p => p.DictType_ID == this.lblDictType.Tag.ToString();
var queryNode = expression.ToExpressionNode();
return queryNode;
}
private void BindData()
{
#region 添加别名解析
this.winGridViewPager1.DisplayColumns = \"Name,Value,Seq,Remark,EditTime\";
this.winGridViewPager1.AddColumnAlias(\"ID\", \"编号\");
this.winGridViewPager1.AddColumnAlias(\"DictType_ID\", \"字典大类\");
this.winGridViewPager1.AddColumnAlias(\"Name\", \"项目名称\");
this.winGridViewPager1.AddColumnAlias(\"Value\", \"项目值\");
this.winGridViewPager1.AddColumnAlias(\"Seq\", \"字典排序\");
this.winGridViewPager1.AddColumnAlias(\"Remark\", \"备注\");
this.winGridViewPager1.AddColumnAlias(\"Editor\", \"修改用户\");
this.winGridViewPager1.AddColumnAlias(\"EditTime\", \"更新日期\");
#endregion
if (this.lblDictType.Tag != null)
{
ExpressionNode condition = GetCondtionSql();
WHC.Pager.Entity.PagerInfo pagerInfo = this.winGridViewPager1.PagerInfo;
IList list = CallerFactory.Instance.FindWithPager(condition, ref pagerInfo);
//this.winGridViewPager1.PagerInfo.RecordCount = pagerInfo.RecordCount;
this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList(list);
}
}
我们在Facade接口实现端,就需要把ExpressionNode反过来变成Expression
///
/// 根据条件查询数据库,并返回对象集合
///
/// 条件表达式
///
public virtual IList Find(ExpressionNode match)
{
Expression> mappedSelector = ConvertExpression(match);
IList tList = baseBLL.Find(mappedSelector);
return tList.MapToList();
}
///
/// 根据条件查询数据库,并返回对象集合(异步)
///
/// 条件表达式
///
public virtual async Task> FindAsync(ExpressionNode match)
{
Expression> mappedSelector = ConvertExpression(match);
IList tList = await baseBLL.FindAsync(mappedSelector);
IList collection = tList.MapToList();
return await Task>.FromResult(collection);
}
这样我们就可以很好利用Entity Framework 实体框架的LINQ表达式进行查询了。
上面的查询代码里面,我们注意到了,条件里面只有一个条件,如下代码。
private ExpressionNode GetCondtionSql()
{
Expression> expression = p => p.DictType_ID == this.lblDictType.Tag.ToString();
var queryNode = expression.ToExpressionNode();
return queryNode;
}
那么对于有多个条件的话,处理就需要特殊处理了,否则就没法组合多个条件进行查询了,多个条件的处理是如何的呢?
如对于日志查询界面来说,如果是采用条件语句的方式,需要使用下面的代码组装语句,然后通过接口方法进行获取数据。
///
/// 根据查询条件构造查询语句
///
private string GetConditionSql()
{
SearchCondition condition = new SearchCondition();
condition.AddCondition(\"LoginName\", this.txtLoginName.Text, SqlOperator.Like);
condition.AddCondition(\"FullName\", this.txtRealName.Text, SqlOperator.Like);
condition.AddCondition(\"Note\", this.txtNote.Text, SqlOperator.Like);
condition.AddCondition(\"IPAddress\", this.txtIPAddress.Text, SqlOperator.Like);
condition.AddCondition(\"MacAddress\", this.txtMacAddress.Text, SqlOperator.Like);
if (dateTimePicker1.Text.Length > 0)
{
condition.AddCondition(\"LastUpdated\", Convert.ToDateTime(dateTimePicker1.DateTime.ToString(\"yyyy-MM-dd\")), SqlOperator.MoreThanOrEqual);
}
if (dateTimePicker2.Text.Length > 0)
{
condition.AddCondition(\"LastUpdated\", Convert.ToDateTime(dateTimePicker2.DateTime.AddDays(1).ToString(\"yyyy-MM-dd\")), SqlOperator.LessThanOrEqual);
}
string systemType = this.txtSystemType.GetComboBoxValue();
if (!string.IsNullOrEmpty(systemType))
{
condition.AddCondition(\"SystemType_ID\", systemType, SqlOperator.Equal);
}
//如果是公司管理员,增加公司标识
if (Portal.gc.UserInRole(RoleInfo.CompanyAdminName))
{
condition.AddCondition(\"Company_ID\", Portal.gc.UserInfo.Company_ID, SqlOperator.Equal);
}
string where = condition.BuildConditionSql().Replace(\"Where\", \"\");
//如果是单击节点得到的条件,则使用树列表的,否则使用查询条件的
if (!string.IsNullOrEmpty(treeConditionSql))
{
where = treeConditionSql;
}
return where;
}
这里有很多条件,通过 SearchCondition 对象,我们能够很方便组合多个条件的查询,然后生成所需的条件语句就可以了,那么对于实体框架里面,我们需要采用Lamda表达式的话,应该如何构建对象并传入给接口方法呢,代码如下所示。
///
/// 根据查询条件构造查询语句
///
private ExpressionNode GetConditionSql()
{
Expression> expression = p => true;
if (!string.IsNullOrEmpty(this.txtLoginName.Text))
{
expression = expression.And(x => x.LoginName.Contains(this.txtLoginName.Text));
}
if (!string.IsNullOrEmpty(this.txtRealName.Text))
{
expression = expression.And(x => x.FullName.Contains(this.txtRealName.Text));
}
if (!string.IsNullOrEmpty(this.txtNote.Text))
{
expression = expression.And(x => x.Note.Contains(this.txtNote.Text));
}
if (!string.IsNullOrEmpty(this.txtIPAddress.Text))
{
expression = expression.And(x => x.IPAddress.Contains(this.txtIPAddress.Text));
}
if (!string.IsNullOrEmpty(this.txtMacAddress.Text))
{
expression = expression.And(x => x.MacAddress.Contains(this.txtMacAddress.Text));
}
if (dateTimePicker1.Text.Length > 0)
{
expression = expression.And(x => x.LastUpdated >= Convert.ToDateTime(dateTimePicker1.DateTime.ToString(\"yyyy-MM-dd\")));
}
if (dateTimePicker2.Text.Length > 0)
{
expression = expression.And(x => x.LastUpdated <= Convert.ToDateTime(dateTimePicker2.DateTime.AddDays(1).ToString(\"yyyy-MM-dd\")));
}
string systemType = this.txtSystemType.GetComboBoxValue();
if (!string.IsNullOrEmpty(systemType))
{
expression = expression.And(x => x.SystemType_ID == systemType);
}
//如果是公司管理员,增加公司标识
if (Portal.gc.UserInRole(RoleInfo.CompanyAdminName))
{
expression = expression.And(x => x.Company_ID == Portal.gc.UserInfo.Company_ID);
}
//如果是单击节点得到的条件,则使用树列表的,否则使用查询条件的
if (treeCondition != null)
{
expression = treeCondition;
}
return expression.ToExpressionNode();
}
这里我们注意到expression.And或者expression.Or函数,它不是这个expression对象的方法的,是我们针对这个做的一个扩展类函数,它专门处理 Lamda-Expression表达式的扩展,方便组合多个条件,如两个表达式条件可以组合为AND或者OR条件方式。
这样我们在界面处理的时候,绑定数据的处理方法就可以如下所示了。
public void BindData()
{
#region 添加别名解析
this.winGridViewPager1.DisplayColumns = \"ID,User_ID,LoginName,FullName,Company_ID,CompanyName,Note,IPAddress,MacAddress,SystemType_ID,LastUpdated\";
this.winGridViewPager1.ColumnNameAlias = CallerFactory.Instance.GetColumnNameAlias();//字段列显示名称转义
#endregion
ExpressionNode where = GetConditionSql();
PagerInfo PagerInfo = this.winGridViewPager1.PagerInfo;
IList list = CallerFactory.Instance.FindWithPager(where, ref PagerInfo);
this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList(list);
}
以上就是我对于混合型的Entity Framework 实体框架的界面操作,总结的几种分析场景,希望对大家理解在WCF模式里面,使用实体框架的方法有所帮助。
上一篇:Entity Framework 实体框架的形成之旅–界面操作的几个典型的处理(8)
下一篇:Entity Framework 实体框架的形成之旅–Code First模式中使用 Fluent API 配置(6)