ERP 高级查询(Advanced Query)设计与实现 SQL语句解析成LLBL Gen ORM代码
2013-06-07 10:39
1191 查看
ERP高级查询(AdvancedQuery)设计与实现SQL语句解析成LLBLGenORM代码
对于开始接触基于ORM技术开发的ERP程序,在相当长的时间内还是会考虑SQL语句,而不是ORM查询。即便是在很熟悉ORM查询,也不如对SQL语句的了解程度。于是想做出一个查询工具,把SQL语句转化为C#代码,用于查询。这样的程序片段在很多地方都需用用到。
比如SQL语句
SELECTRECNUM,CCY,DESCRIPTION,SUSPENDED,DEFAULT_RATEFROM[Currency]
查询当前的货币及其名称,默认汇率。打开高级查询功能,把这几个字段拖动到SQL语句窗口中,点击按钮Execute即可在结果窗格中看到生成的ORM语句片段。
生成的LLBLGenPro代码片段
ICurrencyManagercurrencyManager=ClientProxyFactory.CreateProxyInstance<ICurrencyManager>(); ExcludeIncludeFieldsListfieldlist=newExcludeIncludeFieldsList(false); fieldlist.Add(CurrencyFields.RECNUM); fieldlist.Add(CurrencyFields.CCY); fieldlist.Add(CurrencyFields.DESCRIPTION); fieldlist.Add(CurrencyFields.SUSPENDED); fieldlist.Add(CurrencyFields.DEFAULT_RATE); CurrencyEntitycurrency=currencyManager.GetCurrency(this.,null,fieldlist);
再来分析一下,如何实现这个过程。
1树结点多选功能
如上图中所示,我选中树节点Currency中的多个字段,然后把它拖动到SQL语句窗口中,自动生成SQL查询语句。这里要实现树节点多选功能。WinForms内置的树控件不支持此功能,需要另找控件。这里,我选用CodeProject上的控件MultiSelectTreeView,它的功能用法如下介绍所示
SummarydescriptionforMultiSelectTreeView. TheMultiSelectTreeViewinheritsfromSystem.Windows.Forms.TreeViewtoallowusertoselectmultiplenodes.Theunderlyingcomctl32TreeViewdoesn'tsupportmultipleselection.HencethisMultiSelectTreeViewlistensfortheBeforeSelect&&AfterSelect eventstodynamicallychangetheBackColoroftheindividualtreenodesto denoteselection.ItthenaddstheTreeNodetotheinternalarraylistofcurrentlyselectedNodesaftervalidationchecks. TheMultiSelectTreeViewsupports 1)Select+ControlwilladdthecurrentnodetolistofSelectedNodes 2)Select+Shitftwilladdthecurrentnodeandallthenodesbetweenthetwo (ifthestartnodeandendnodeisatthesamelevel) 3)Control+AwhentheMultiSelectTreeViewhasfocuswillselectallNodes.
2鼠标拖动编程
树结点中设置AllowDrag,加入事件响应方法ItemDragprivatevoidtreeTables_ItemDrag(objectsender,ItemDragEventArgse) { if(e.Button==MouseButtons.Left) { DoDragDrop(e.Item,DragDropEffects.Copy); } }
要拖进的SQLTextEdtor,则对它加入事件响应方法
privatevoidtxtSqlScript_DragDrop(objectsender,DragEventArgse) { TreeNodedraggedNode=(TreeNode)e.Data.GetData(typeof(TreeNode)); if(draggedNode.Tag=="Column") { List<string>columns=newList<string>(); foreach(TreeNodenodeintreeTables.SelectedNodes) { columns.Add(node.Text.Substring(0,node.Text.IndexOf("("))); } stringtableName=draggedNode.Parent.Text; stringsql=string.Format("SELECT{0}FROM[{1}]",string.Join(",",columns),tableName); txtSqlScript.InsertText(sql); } elseif(draggedNode.Tag=="Table") { txtSqlScript.InsertText(string.Format("[{0}]",draggedNode.Text)); } }
这几句话,根据节点代表的含义(字段,表名),来构造SQL查询语句。
3SQL语句解析
VisualStudioDatabaseEdition提供了SQL语句解析功能,引用这两个程序集,实现类似的代码publicstaticstringExecute(QueryDataSourcedataSource,stringsql) { stringcsharpCode=string.Empty; IList<ParseError>Errors; varparser=newTSql100Parser(false); StringReaderreader=newStringReader(sql); IScriptFragmentresult=parser.Parse(reader,outErrors); varScript=resultasTSqlScript; foreach(vartsinScript.Batches) { foreach(varstints.Statements) { IterateStatement(st,refcsharpCode,dataSource); } } returncsharpCode; }
此方法根据传入的SQL语句,返回C#代码。LLBLGen是一项ORM技术,ORM首要解决的问题是C#代码如何转化为对数据库操作的SQL语句。在这里,我把这个过程反过来,根据SQL语句,得到C#代码。
数据表Currency对应的程序中的实体类型是CurrencyEntity,它的字段RECNUM对应于C#实体类型CurrencyEntity中的Recnum,这个映射关系存储于生成的C#代码中。
///<summary>InitsCurrencyEntity'smappings</summary> privatevoidInitCurrencyEntityMappings() { this.AddElementMapping("CurrencyEntity","MIS",@"dbo","Currency",29); this.AddElementFieldMapping("CurrencyEntity","AcctApForex","ACCT_AP_FOREX",true,"NVarChar",30,0,0,false,"",null,typeof(System.String),0); this.AddElementFieldMapping("CurrencyEntity","AcctArForex","ACCT_AR_FOREX",true,"NVarChar",30,0,0,false,"",null,typeof(System.String),1); this.AddElementFieldMapping("CurrencyEntity","ApInvoBal","AP_INVO_BAL",true,"Decimal",0,2,16,false,"",null,typeof(System.Decimal),2); this.AddElementFieldMapping("CurrencyEntity","ApLinvoBal","AP_LINVO_BAL",true,"Decimal",0,2,16,false,"",null,typeof(System.Decimal),3); this.AddElementFieldMapping("CurrencyEntity","ApLnetBal","AP_LNET_BAL",true,"Decimal",0,2,16,false,"",null,typeof(System.Decimal),4); this.AddElementFieldMapping("CurrencyEntity","ApLopenBal","AP_LOPEN_BAL",true,"Decimal",0,2,16,false,"",null,typeof(System.Decimal),5); this.AddElementFieldMapping("CurrencyEntity","ApNetBal","AP_NET_BAL",true,"Decimal",0,2,16,false,"",null,typeof(System.Decimal),6); }
运行时,只需要调用此方法即可得到它们的映射关系,以实现将SQL语句的object(table,column)转化为C#程序对应的object(Entity,property)。
4Debug功能的实现
为了实现即使运行效果,将上面的生成的SQL语句,编译成C#程序集,再执行程序集,得到返回的结果。CodeDomProvidercodeProvider=null; if(Language==LanguageType.CSharp) codeProvider=newCSharpCodeProvider(); elseif(Language==LanguageType.VB) codeProvider=newVBCodeProvider(); //createthelanguagespecificcodecompiler ICodeCompilercompiler=codeProvider.CreateCompiler(); //addcompilerparameters CompilerParameterscompilerParams=newCompilerParameters(); compilerParams.CompilerOptions="/target:library";//youcanadd/optimize compilerParams.GenerateExecutable=false; compilerParams.GenerateInMemory=true; compilerParams.IncludeDebugInformation=false; //addsomebasicreferences compilerParams.ReferencedAssemblies.Add("mscorlib.dll"); compilerParams.ReferencedAssemblies.Add("System.dll"); compilerParams.ReferencedAssemblies.Add("System.Data.dll"); compilerParams.ReferencedAssemblies.Add("System.Drawing.dll"); compilerParams.ReferencedAssemblies.Add("System.Xml.dll"); compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
如果团队中允许多语言并行开发,此功能也可以实现将生成的C#代码,转化为VB代码。
在这里,需要构造一个Main方法,把生成的代码嵌入到这个Main方法中去,返回一个对象,把这个对象反射到Debug的网格窗口中。反射调用的入口方法如下所示
privateobjectCallEntry(Assemblyassembly,stringentryPoint)
{
objectresult=null;
try
{
//UsereflectiontocallthestaticMainfunction
Module[]mods=assembly.GetModules(false);
Type[]types=mods[0].GetTypes();
foreach(Typetypeintypes)
{
MethodInfomi=type.GetMethod(entryPoint,
BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static);
if(mi!=null)
{
if(mi.GetParameters().Length==1)
{
if(mi.GetParameters()[0].ParameterType.IsArray)
{
string[]par=newstring[1];//ifMainhasstring[]arguments
result=mi.Invoke(null,par);
}
}
else
{
result=mi.Invoke(null,null);
}
}
}
LogErrMsgs("Enginecouldnotfindthepublicstatic"+entryPoint);
}
catch(Exceptionex)
{
LogErrMsgs("Error:Anexceptionoccurred",ex);
}
returnresult;
}
最后一步,绑定结果到网格中
voidBindEntity2Grid(IEntity2entity)
{
grid.RowHeadersVisible=false;
grid.AutoGenerateColumns=false;
grid.Columns.Clear();
Typetype=entity.GetType();
PropertyInfo[]propertyInfos=type.GetProperties();
for(inti=0;i<propertyInfos.Length;i++)
{
PropertyInfoproperty=propertyInfos[i];
if(excludeColumns.Contains(property.Name))
continue;
DataGridViewTextBoxColumncolumn=newDataGridViewTextBoxColumn();
column.HeaderText=property.Name;
column.DataPropertyName=property.Name;
column.Name=property.Name;
grid.Columns.Add(column);
}
for(inti=0;i<propertyInfos.Length;i++)
{
PropertyInfoproperty=propertyInfos[i];
if(excludeColumns.Contains(property.Name))
continue;
grid.Rows[0].Cells[property.Name].Value=ReflectionHelper.GetPropertyValue(entity,property.Name);
}
}
这里的目的是读取对象的属性,生成Grid的列,并填充值。
这里使用的SQL语法高亮控件来自于CodeProject的FastColoredTextBox。读取一个数据库中所有的表及表的字段用到如下的SQL语句,供您参考。
SELECTnameFROMsysobjectsWHERExtype='U'
SELECTsyscolumns.NAMEAS[ColumnName],systypes.NAMEAS[ColumnType],syscolumns.lengthAS[ColumnLength],syscolumns.isnullableAS[Nullable]FROMsyscolumns
leftjoinsystypesonsyscolumns.xusertype=systypes.xusertype
WHEREid=(selectidfromsysobjectswherename='Currency‘
此功能有个明显的Bug,没有把功能编码显示在地址栏中,因为它继承于FormBase,需要改成FunctionFormBase可达到目的,界面可能需要重新排版一下,改变继承的基类会让窗体设计器重新加载基类控件,子类的控件会丢失。
[FunctionCode("SAUMAQ")]
publicpartialclassAdvancedQuery:FormBase
{
privatestring_fileName;
publicAdvancedQuery()
{
InitializeComponent();
}
}
相关文章推荐
- (转)ERP 高级查询(Advanced Query)设计与实现 SQL语句解析成LLBL Gen ORM代码
- ERP 高级查询(Advanced Query)设计与实现 SQL语句解析成LLBL Gen ORM代码
- mysql 查询指定日期时间内sql语句实现原理与代码
- Sql语句与存储过程查询数据的性能测试实现代码
- 一个通用的单元测试框架的思考和设计08-实现篇-在testcase代码中执行sql语句
- 一个通用的单元测试框架的思考和设计08-实现篇-在testcase代码中执行sql语句
- 自己实现一个SQL解析引擎 功能:将用户输入的SQL语句序列转换为一个可执行的操作序列,并返回查询的结果集。 SQL的解析引擎包括查询编译与查询优化和查询的运行,主要包括3个步骤: 查询分析
- Enterprise Solution 3.1 企业应用开发框架 .NET ERP/CRM/MIS 开发框架,C/S架构,SQL Server + ORM(LLBL Gen Pro) + Infragistics WinForms
- Sql语句与存储过程查询数据的性能测试实现代码
- mysql 查询指定日期时间内sql语句实现原理与代码
- sql语句解析实现
- 用SQL语句实现随机查询数据并不显示错误数据的方法
- 在DataSet实现类似sql语句的查询
- [转]在Excel中使用SQL语句实现精确查询
- sql语句结构之查询语句(内含代码示例)
- 协会网站代码review之SQL实现模糊查询
- ORACLE和SYBASE数据库中实现数据查询条数限制的SQL语句实现
- mysql中sql实现查询当天、昨天、本月、季度的语句
- SQL高级语句-CREATE INDEX 在表中创建索引,以便更加快速高效地查询数据。
- mongodb条件查询实现结构化查询语句SQL