避免重复劳动-C# 实体类生成工具下载(WPF)
时间:2010-09-02 来源:Dennis.Yang
小软开发手记
先讲讲开发目的:为了不再很机械的复制粘贴复制再粘贴,往返于VS和SQL中间,于是上网找有没有自动生成实体类的东西。找了一圈,发现有是有,不过都不是自己需要的,有的功能太强,有的界面不够简洁,其实我要求的功能挺少挺简单的,但是就是找不到,很郁闷~ 于是决定自己花点时间写一个。
刚开始的目的仅限于此,后面慢慢说开发过程,遇到的问题和解决方案,希望这个软件可以给大家带来方便,开发过程中的一些经验也对大家有帮助。
第一天
我做的事情:
1. 软件的架构工作,汇报如下:
软件需求:(1)根据用户输入的DB Server的信息(IP,User,Password)自动获取Server上的DB列表(有改进)
(2)根据用户选择的DB,读出所有的Table和对应Table上的所有字段,做成List (有改进)
(3)根据用户单击的的Table自动生成该Table的实体类(有改进)
开发环境和语言: VS2010, C#, WPF
2. MainWindow的Layout设计和Coding
这部分为需求(1),刚开始想的简单,拖几个TextBox然后让用户输入一些信息,然后再把得到的数据库绑定到一个Combobox就算OK。于是开始做界面。
这部分的主要代码如下:

string connStr = "";
if (ChkIsWindows.IsChecked != true)
{
connStr = string.Format(
"Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}",
dataSource, inCa, uid, pwd);
}
else
{
connStr = string.Format(
"Data Source={0};Initial Catalog={1};Trusted_Connection=SSPI", dataSource,"Master");
}
_sqlstr = "Select Name From Master..sysdatabases";
return SqlUtility.GetDataTableBySqlStr(connStr, _sqlstr, out errMsg);
如上,第一个分支判断是否为使用系统验证的,两种登入SQL Server的方式,连接字符串是不同的。
做完了后的界面如下:
怎么样? 还比较清爽吧? 选中第一个复选框会自动带出DB Server 和 Login ID, Password也不用填了。
第二天
我做的事情:
1. 主窗口,用作自动生成代码的界面设计
2. 需求(2)的功能实现和软件性能优化,如何能快速的读出远程
这部分是主要部分,良好的用户体验是必不可少的,开始的想法太简单,并且不易用,因为肯定有很多人想一次生成很多Table的实体,或者只想为部分字段做属性。
于是我决定使用TreeView空间,Table作为主节点,字段作为子节点。然后在每个节点处加入CheckBox用来限制选定与否。这些都是在程序中控制的。
3. 初始化一个Tab用来放置文本模板,这样用户就可以自定义文本生成模板了,使用范围就更广了(今天刚发现,这个用来把读取的DataSet中的Column数据都赋值到对应的实体中也是很方便的)
主要代码如下:

#region Init TreeView
private void InitDtList()
{
string errMsg;
DataTable tbList = GetTbList(out errMsg);
if (!string.IsNullOrEmpty(errMsg))
{
TxtNote.Text = errMsg;
return;
}
if (tbList != null && tbList.Rows.Count > 0)
{
TrvTbList.Items.Clear();
for (int i = 0; i < tbList.Rows.Count; i++)
{
CheckBox cb = new CheckBox
{
Content = tbList.Rows[i][0].ToString(),
Tag = i
};
cb.Click += CbTable_Click;
TreeViewItem tvItem = new TreeViewItem
{
Header = cb,
};
TrvTbList.Items.Add(tvItem);
InitColumnList(tvItem, tbList.Rows[i][0].ToString());
}
}
else
{
TxtNote.Text = string.Format("No Table in DataBase: {0}", Program.SelectedDb);
}
}
private void InitColumnList(TreeViewItem tvItemHeader, string dtName)
{
string errMsg;
DataTable columnList = GetColumnList(dtName, out errMsg);
if (!string.IsNullOrEmpty(errMsg))
{
TxtNote.Text = errMsg;
return;
}
if (columnList != null && columnList.Rows.Count > 0)
{
tvItemHeader.Items.Clear();
for (int i = 0; i < columnList.Rows.Count; i++)
{
string[] types = Program.GetTypeById(columnList.Rows[i][1].ToString());
CheckBox subCb = new CheckBox
{
Content = string.Format("{0} (SQL: {1})", columnList.Rows[i][0], types[0]),
Tag = types,
ToolTip = columnList.Rows[i][0]
};
TreeViewItem tvSubItem = new TreeViewItem
{
Header = subCb,
ToolTip = "C#: " + types[1]
};
tvItemHeader.Items.Add(tvSubItem);
}
}
}
private DataTable GetTbList(out string errMsg)
{
_sqlstr = "Select Name From SysObjects Where XType='U' order By Name";
return SqlUtility.GetDataTableBySqlStr(Program.Connstr, _sqlstr, out errMsg);
}
private DataTable GetColumnList(string dtName, out string errMsg)
{
_sqlstr =
string.Format(
@"select sc.name as Name,sc.xtype as Type from syscolumns sc,sysobjects so
where sc.id = so.id and so.name = N'{0}'", dtName);
return SqlUtility.GetDataTableBySqlStr(Program.Connstr, _sqlstr, out errMsg);
}
然后就是根据用户的选择自动生成代码了,这里我用了TabControl空间,然后动态添加TabItem。代码如下:

#region Add Tabs
private void AddEntityTabsByTreeView(TreeView tv)
{
string tempStr = ((TextBox)tabItem0.Content).Text;
foreach (var item in tv.Items)
{
string entityStr = "";
CheckBox cb = ((TreeViewItem)item).Header as CheckBox;
if (cb != null && cb.IsChecked == true)
{
foreach (var subItem in ((TreeViewItem)item).Items)
{
CheckBox subCb = ((TreeViewItem)subItem).Header as CheckBox;
if (subCb != null && subCb.IsChecked == true && !string.IsNullOrEmpty(tempStr))
{
entityStr += tempStr.Replace("%ColummName%", subCb.ToolTip.ToString()).Replace("%ColummType%",
((string[])subCb.Tag)[
1]) + "\n";
}
}
if (!string.IsNullOrEmpty(entityStr))
{
TabItem tabItem = new TabItem { Header = cb.Content };
TextBox tb = new TextBox { Text = entityStr };
tb.TextWrapping = TextWrapping.Wrap;
tb.AcceptsReturn = true;
tb.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
tabItem.Content = tb;
TabEntity.Items.Add(tabItem);
}
}
}
}
#endregion
做完了后的界面如下:
注意,这里我是使用一个xml文件来做类型映射的,第二天完工...
第三天
我做的事情:
1. 加入了一些常用功能,比如后退,退出,重置,当前Tab的文本Copy等等
2. 页面控件的重新布局
3. 加入了错误信息的提示
4. 重头戏,程序代码的优化,使用了少少的全局变量,从而大量减少了远程连接时的超时现象

public static string[] GetTypeById(string typeId)
{
if (TypeDic == null || !TypeDic.ContainsKey(typeId))
{
string mapFile = "TypeMap.xml";
DataSet ds = new DataSet();
ds.ReadXml(mapFile);
if (ds.Tables["type"] == null && ds.Tables["type"].Rows.Count <= 0)
{
return null;
}
TypeDic = new Dictionary<string, string[]>();
for (int i = 0; i < ds.Tables["type"].Rows.Count; i++)
{
string[] dataTypes = new string[2];
dataTypes[0] = ds.Tables["type"].Rows[i][0].ToString();
dataTypes[1] = ds.Tables["type"].Rows[i][2].ToString();
if (!TypeDic.ContainsKey(ds.Tables["type"].Rows[i][1].ToString()))
{
TypeDic.Add(ds.Tables["type"].Rows[i][1].ToString(), dataTypes);
}
}
}
return TypeDic[typeId];
}
5. 使用Config文件,便于用户的配置
好了,完工了,就说到这,希望对大家有用。
送上小软,希望能提点改进建议,写的不好,大家见笑了。
不能上传附件... 放在自己的网站了,点击下载 AutoEntity