[转载]工欲善其事必先利其器---SQL在线可视化模型设计,(还可学习拖拽知识) - 沫尘 - 博客园

[转载]工欲善其事必先利其器—SQL在线可视化模型设计,(还可学习拖拽知识) – 沫尘 – 博客园.

作为技术人员,在开发项目中,不可避免的要跟数据库打交道,一个完整的项目正常情况下是讨论完整体需求,有了大致的框框在脑海中后,是需要设计合理的数据 库的,这时会有其他的专业的UML建模工具可以使用, 但是这种大型的专业化的UML建模工具,仅仅拿来建立数据库模型显得大材小用了,并且也太重量级,所以一般都不会轻易使用。多数人会选择直接在数据库软件 中直接鼠标操作建表、填充列, 这样更是不方便,  故而很多人提到了VS中的codefirst方式,  直接在代码中建立数据库模型,  这种方式生成数据库之后,如果回头维护、查看都不太友好,甚至过了几个月之后你自己回头看都有可能不知道是什么意思。  这样我们就需要数据库说明。

常见的数据库说明都是word文档,类似如下:

这是很多公司或团队采用的, 但是我觉得这样还是不爽,假定你是一个接手人, 你拿着这样的表格,左边点开数据库,右边打开这个文档,瞄一眼数据库再瞄一眼这个表格,左右切换窗口,超级不爽啊。

另外一种更加直观的,正向思维的方式:

 

这样看起来是不是直观多了,  清楚明白的知道这个表的构成,直接在数据库中打开,不用切换窗口,它是建表脚本,也是一份详细直观的数据库说明文档, 后续对数据库进行修改、增加、删除结构都很直接、直观。

于是,我个人就弄了个自己用的方便的可视化的数据库设计的东西,当然最终是生成上述直观可读性高的脚本文件,今天把它写出来分享下。

我的环境是mvc3,  其实这个东西根本用不着MVC,  很简单,就一个页面大量的JS操作,提交到后台代码生成文件下载回本地。先看打开时:

默认加载一个空表,填写相应的名称之类的,字段、类型、默认值、备注信息等,+号增加一行,如果一行没有完成会提示:

点击新建表会增加一个表,整个筐筐内每个表模型可以任意拖动位置且高度会自适应。拖拽都是靠JS。整个界面代码如下:

@{
ViewBag.Title = "主页";
}
<div class="box">
<div class="editmenu">

<input id="txtBaseName" type="text" value="@ViewBag.baseName" />

<input id="txtBaseDes" type="text" value="@ViewBag.baseDes" />
<input id="addTable" type="button" value="新建表" />
<input id="getData" style="float: right;" title="下载完整的TXT格式的数据库脚本" type="button" value="下载数据" />

</div>
<div class="main" id="main">
<div class="tbbox">
<div class="titletr" title=""><span class="spleft">
<input class="tbname" type="text" value="XXX表" />
</span>
</div>
<div class="titletr" title=""><span class="spleft">
名:<input class="tbname" type="text" value="tb_1" />
</span>

<span class="spright">删除</span></div>
<table class="tablelist">
<tbody>
<tr>
<td>字段名</td>
<td>类型</td>
<td>默认值</td>
<td>备注</td>
<td style="border: 0;"></td>
</tr>
<tr>
<td><input type="text" /></td>
<td>
<div class="sortdiv"><span class="selspan"><span class="selspan"><select class="selsort"><option value="int">int</option><option value="varchar(50)">varchar(50)</option><option value="nvarchar(200)">nvarchar(200)</option><option value="datetime">datetime</option><option value="float">float</option><option value="text">text</option><option value="ntext">ntext</option></select></span></span>&nbsp;
<input class="sortinput" type="text" value="int" /></div></td>
<td><input class="txtdef" type="text" /></td>
<td><input type="text" /></td>
<td class="jiatr" id="tool" style="border: 0;">+</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<input id="hdbase" type="hidden" value="@ViewBag.baseId" />

<input id="hdtr" type="hidden" value="@ViewBag.Tr" />
<input id="hddiv" type="hidden" value="@ViewBag.div" />
<input id="hdall" type="hidden" value="@ViewBag.AllData" />

<script type="text/javascript">// <![CDATA[
        $(document).ready(function () {
            window.onload = function () {
                if ($("#hdall").val() != "") {
                    $("#main").html($("#hdall").val());
                }
                ///初始化给div加移动事件
                $("#main").find("span.title").each(function () {
                    this.onmousedown = MoveBegin;
                });
                ///给+TD事件
                $("#main").find("td.jiatr").each(function () {
                    $(this).click(TdClick);
                    $(this).attr("title", "新增一行");
                });
                ///添加DIV按钮
                $("#addTable").click(AddTbale);
                $("#getData").click(GetData);
                $("#saveData").click(SaveData);
                ///给select绑定事件
                $("#main").find("div.tbbox").each(function () {
                    SortList(this);
                    $(this).find("span.spright").click(DelDiv);
                });

                CheckMainHeight();

            }
            ///返回txt文件
            function SaveTxt(arr) {
                var loogParam = arr;
                var nwin = window.open('/home/DataText?t=' + Math.random(), 'newwindow', 'height=5, width=5, top=400,left=500, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=no, status=no');
                document.body.insertAdjacentHTML("beforeEnd", "
<form  name='form1'  action='/home/DataText'  target='newpage'  method='post'><input  type='hidden'  name='param'></form>

");
                document.form1.param.value = loogParam;
                document.form1.submit();
                $("form").remove();
                nwin.close();
            }

            ///txt文件空格占位
            function NullSpace(defnum, str) {
                var s = "\040";
                var r = "";
                var l = str.length;
                var num = defnum - l;
                for (var i = 0; i < num; i++) {
                    r += s;
                }
                return r;
            }
            ///"-"占位符
            function NullH(defnum, str) {
                var s = "-";
                var r = "";
                var l = str.length;
                var num = defnum - l;
                for (var i = 0; i < num; i++) {                     r += s;                 }                 return r;             }                          ///下载脚本为txt文件             function GetData() {                 var tbName = "";                 var tr = 0;                 var sav = true;                 var br = "\r\n";                 var strSql = "use  " + $("#txtBaseName").val() + br;                 $("#main").find("div.tbbox").each(function () {                     tbName = $($(this).find(".tbname")[1]).val();                     var desName = $($(this).find(".tbname")[0]).val();                     var sqlExists = "if exists ( select *  from  sysobjects where name = '" + tbName + "' and xtype='U') " + br + ""                                 + "drop table " + tbName + "";                     strSql += sqlExists + br;                     strSql += "create table  " + tbName + NullH(67, tbName) + desName + br + "(" + br;                     $(this).find("tr").each(function (index, element) {                         if (index > 0) {
                            var tdlist = $(this).find("td");
                            var key = $(tdlist[0]).find("input").val();
                            if ($.trim(key) != "") {
                                if (key.length >= 17) {
                                    alert(key + "超出了15个字符的限制");
                                    //alert(strSql);
                                    sav = false;
                                    return;
                                }
                                key += NullSpace(17, key);
                                var col = $(tdlist[1]).find("input").val();
                                col += NullSpace(17, col);
                                if (index == 1)
                                    col = "int" + NullSpace(17, "int");
                                var def = $(tdlist[2]).find("input").val() == "" ? "default ''" : "default  " + $(tdlist[2]).find("input").val();
                                def += NullSpace(32, def);
                                if (index == 1)
                                    def = "primary key identity(1,1)" + NullSpace(32, "primary key identity(1,1)");
                                var des = "--" + $(tdlist[3]).find("input").val();
                                if (index == 1)
                                    des = "--主键-" + $(tdlist[3]).find("input").val();
                                strSql += "\040\040" + key + col + def + "NOT NULL , " + des + br;

                                tr++;
                            }
                        }
                    });
                    strSql += ");" + br + br + br;
                });
                if (sav && tr > 0) {
                    $("#saveData").click();
                    SaveTxt(strSql);
                }
            }

            ///给数据类型列加事件
            function SortList(obj) {
                $(obj).find("div.sortdiv").each(function () {

                    $(this).find("select:first").change(ChangeVal).change(DefaultTxt);
                    $(this).find("input:first").focus(ShowSel);

                    $(this.parentNode).mouseenter(ShowSel).mouseleave(HideSel);

                    $(this.parentNode.parentNode).find(".txtdef").blur(DefaultTxt);

                });

            }

            ///删除div
            function DelDiv() {
                $(this.parentNode.parentNode).remove();
            }

            ///改变数据类型
            function ChangeVal(obj) {
                $(this.parentNode.parentNode).find(".sortinput").val($(this.parentNode).find(".selsort").val());

            }
            ///默认值
            function DefaultTxt(obj) {
                var txt = $(this.parentNode.parentNode).find(".txtdef:first")[0];
                if (obj.type == "change") {
                    txt = $(this.parentNode.parentNode.parentNode.parentNode).find(".txtdef:first")[0];
                }
                var val = $(txt).val().replace("'", "").replace("'", "");
                $(txt).val(val);
                if ($.trim($(txt).val()) != "" && $.trim($(txt).val().toLowerCase()) != "getdate()" && $.trim($(txt.parentNode.parentNode).find(".sortinput").val()) != "int" && $.trim($(txt.parentNode.parentNode).find(".sortinput").val()) != "float") {

                    $(txt).val("'" + val + "'");
                }
            }
            ///数据类型下拉显示
            function ShowSel(obj) {
                $(this.parentNode).find(".selspan").show();
                $(this.parentNode).find(".sortinput").width("90px");
                $(this.parentNode).find(".sortinput").css("position", "absolute");
            }
            ///数据类型下拉隐藏
            function HideSel(obj) {
                var td = this;
                var o = obj.relatedTarget || obj.toElement;
                if (!o) {
                    return;
                }
                $(td).find(".selspan").hide();
                $(td).find(".sortinput").width("118px");
                $(td).find(".sortinput").css("position", "");
            }

            ///添加DIV
            function AddTbale() {
                var child = document.createElement("div");
                child.className = "tbbox";
                var name = Math.random().toString().substr(2, 3);
                var div = $("#hddiv").val().replace("tb_Name", "tb_" + name);
                $(child).html(div);
                $(child).find("span.title").each(function () {
                    this.onmousedown = MoveBegin;
                });

                $(child).find("span.spright").click(DelDiv);
                $(child).find("td.jiatr").each(function () {
                    $(this).click(TdClick);
                    $(this).attr("title", "新增一行");
                });
                SortList(child);
                $("#main").append(child);
                CheckMainHeight();
            }

            ///TD增加一行点击
            function TdClick(obj) {
                var tooltipem = $(this.parentNode).find("td:first").find("input:first");
                if ($.trim(tooltipem.val()) == "") {
                    $(tooltipem).tooltip({
                        "title": "这里还没填写呢~!",
                        "trigger": "manual",
                        "placement": "right",
                        "delay": 800
                    });
                    $(tooltipem).tooltip("show");

                    $(tooltipem).focus();
                    setTimeout(function () { $(tooltipem).tooltip("hide"); }, 1800)

                    return false;
                }
                $(tooltipem).tooltip("destroy");
                var tr = $("#hdtr").val();
                var child = document.createElement("tr");
                $(child).html(tr);
                $(this.parentNode.parentNode).append(child);
                SortList(child);
                $(child).find("td.jiatr").click(TdClick);

                $(this).removeClass();
                $(this).unbind();
                $(this).html("");
                $(this).attr("title", "");

                CheckMainHeight();
                $($($(this.parentNode.parentNode).find("tr:first").next("tr"))).find("td:last").addClass("prmkey").attr("title", "第一行默认为主键&自增长");
            }
            ///校验div#main高度
            function CheckMainHeight() {
                $("#main").find("div").each(function () {
                    if (this.offsetTop + $(this).height() > $("#main").height())
                        $("#main").height(this.offsetTop + $(this).height() + 10);
                });
            }

            ///移动
            function MoveBegin(obj) {
                var e = obj || window.event,
                x1 = e.clientX;
                y1 = e.clientY;
                var setOn = this.parentNode.parentNode;
                var defLeft = setOn.offsetLeft;
                var defTop = setOn.offsetTop;

                document.onmousemove = function (event) {
                    var e = event || window.event;
                    //
                    x2 = e.clientX;
                    y2 = e.clientY;
                    //
                    x = x2 - x1;
                    y = y2 - y1;
                    var setLeft = defLeft + x;
                    var setTop = defTop + y;
                    setOn.style.position = "absolute";
                    //setOn.style.filter = 'alpha(opacity=80)';
                    //setOn.style.opacity = "0.8";
                    if (setLeft <= 0) {
                        setLeft = 0;
                    }
                    if (setTop <= 0) {                         setTop = 0;                     }                     if (setLeft >= $("#main").width() - $(setOn).width() - 9) {
                        setLeft = $("#main").width() - $(setOn).width() - 14;
                    }
                    if (setTop > $("#main").height() - $(setOn).height() + 10) {

                        $("#main").height(setTop + $(setOn).height() + 100);

                        setTop = $("#main").height() - $(setOn).height();
                    }
                    setOn.style.left = setLeft + 'px';
                    setOn.style.top = setTop + 'px';
                    //$("#showText").text("Top:" + setOn.style.top + "; Left:" + setOn.style.left + "; OFl:" + "");
                }
                document.onmouseup = function () {
                    this.onmousemove = null;
                }
            }

        });   

// ]]></script>

里面有JS拖拽代码, 都很简单, 上面这些是我2年前做的东西,很多命名之类的都不规范,大家关注方法就好。

后台代码:

public ActionResult Index()
{
StringBuilder sb = new StringBuilder();

sb.Append("");
sb.Append("<input type="\&quot;text\&quot;" />");
sb.Append("

");
sb.Append("");
sb.Append("
<div class="\&quot;sortdiv\&quot;">");
sb.Append("<span class="\&quot;selspan\&quot;"><span class="\&quot;selspan\&quot;">");
sb.Append("
<select class="\&quot;selsort\&quot;">");</select>
<select class="\&quot;selsort\&quot;">sb.Append("</select>
<select class="\&quot;selsort\&quot;"><option value="\&quot;int\&quot;">int</option></select></span></span>");
sb.Append("
varchar(50)

");
sb.Append("
nvarchar(200)

");
sb.Append("
datetime

");
sb.Append("
float

");
sb.Append("
text

");
sb.Append("
ntext

");
sb.Append("

");
sb.Append("

");
sb.Append("<input class="\&quot;sortinput\&quot;" type="text" value="\&quot;int\&quot;" />");
sb.Append("</div>
");
sb.Append("

&nbsp;

");
sb.Append("");
sb.Append("<input class="\&quot;txtdef\&quot;" type="\&quot;text\&quot;" />");
sb.Append("

");
sb.Append("");
sb.Append("<input type="\&quot;text\&quot;" />");
sb.Append("

");
sb.Append("
");
sb.Append("+");
sb.Append("

");
ViewBag.Tr = sb.ToString();

StringBuilder sbdiv = new StringBuilder();
sbdiv.Append("
<div class="titletr" title="">");
sbdiv.Append("<span class="spleft">");
sbdiv.Append("<input class="tbname" type="text" value="XXX表" />");
sbdiv.Append("</span>");
sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("</div>
");
sbdiv.Append("
<div class="titletr" title="">");
sbdiv.Append("<span class="spleft">");
sbdiv.Append("名:<input class="tbname" type="text" value="tb_Name" />");
sbdiv.Append("</span>");
sbdiv.Append("");
sbdiv.Append("<span class="spright">删除</span>");
sbdiv.Append("</div>
");
sbdiv.Append("

"); sbdiv.Append(""); sbdiv.Append(""); sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("类型");
sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("默认值");
sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append(" 备注");
sbdiv.Append("");
sbdiv.Append("
");
sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("
"); sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("
<div class="sortdiv">
<div class="sortdiv">");
sbdiv.Append("<span class="selspan"><span class="selspan">");
sbdiv.Append("
<select class="selsort">");</select>
<select class="selsort">sbdiv.Append("</select>
<select class="selsort"><option value="int">int</option></select></span></span>");
sbdiv.Append("

</div>
</div>
varchar(50)
<div class="sortdiv">
<div class="sortdiv">

");
sbdiv.Append("

</div>
</div>
nvarchar(200)
<div class="sortdiv">
<div class="sortdiv">

");
sbdiv.Append("

</div>
</div>
datetime
<div class="sortdiv">
<div class="sortdiv">

");
sbdiv.Append("

</div>
</div>
float
<div class="sortdiv">
<div class="sortdiv">

");
sbdiv.Append("

</div>
</div>
text
<div class="sortdiv">
<div class="sortdiv">

");
sbdiv.Append("

</div>
</div>
ntext
<div class="sortdiv">

");
sbdiv.Append("

");
sbdiv.Append("

");
sbdiv.Append("<input class="sortinput" type="text" value="int" />");
sbdiv.Append("</div>
");
sbdiv.Append("

");
sbdiv.Append("");
sbdiv.Append("<input class="txtdef" type="text" />");
sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("<input type="text" />");
sbdiv.Append("");
sbdiv.Append("
");
sbdiv.Append(" +");
sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("");
sbdiv.Append("
<table class="tablelist">
<tbody>
<tr>
<td>");
sbdiv.Append("字段名");
sbdiv.Append("</td>
</tr>
<tr>
<td>");
sbdiv.Append("<input type="text" />");
sbdiv.Append("</td>
</tr>
</tbody>
</table>
");
ViewBag.div = sbdiv.ToString();
ViewBag.AllData = "";
ViewBag.baseId = "";
ViewBag.baseName = "basename";
ViewBag.baseDes = "备注说明";

return View();

}
//响应下载脚本请求,返回txt文件
public void DataText()
{
if (Request["param"] == null)
return;
string t = Request["param"];
if (t == "")
return;
string tbName = "数据库-" + System.DateTime.Now.ToString("yyMMdd-HHmmss")+".sql";
Response.AppendHeader("Content-Disposition", "attachment;filename=" + tbName);
Response.ContentEncoding = System.Text.Encoding.Default;
Response.ContentType = "text/plain";
Response.Write(t);
}

没时间分段说了, 有源码和在线暂时测试地址:http://websql.puworld.com

 

 

源码:http://files.cnblogs.com/mochen/WebSql.zip

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏