MIS系统中的数据查询时必不可少的。而且大部分都是多表查询,这时候SQL语句中的Join就显得尤为重要。再加上现在的O-R mapping,更是给查询带来了一个不大不小的麻烦(我不是说O-R mapping的坏话)。以下的部分将用一个本人认为很典型的例子说明一下。

      数据库结构如下:


      用户界面如下:

      由数据库结构和界面的grid可以很容易想到,直接写上

select FACILITY.*, PROJECT.CODE as PROJECT_CODE, PROJECT.CN_NAME as PROJECT_CN_NAME, SITE.NAME as SITE_NAME, SITE.CID as SITE_CID,
FACILITY_CATALOG.CN_NAME as FACILITY_CATALOG_NAME 
from FACILITY left outer join PROJECT on FACILITY.MASTER_ID = PROJECT.ID left outer join SITE on PROJECT.SITE_GUID = SITE.ID left outer FACILITY_CATALOG on FACILITY.CATALOG_GUID = FACILITY_CATALOG.ID

。然后在后头写上where搜索里选择的条件。这似乎没什么难度吧。

      这个项目典型的地方是使用了一个可爱的框架,绑定在grid上的不是DataTable而是一个EntityCollection,而且这里还用了延迟加载,即使在SQL语句中写上了PROJECT.CODE, PROJECT.CN_NAME,由于延迟加载的关系都被忽略了(Facility这个实体对象里包含MASTER_ID,利用延迟加载来获取实体对象Project)。所以SQL语句就得写成了

select FACILITY.* from FACILITY left outer join PROJECT on FACILITY.MASTER_ID = PROJECT.ID left outer join SITE on PROJECT.SITE_GUID = SITE.ID left outer FACILITY_CATALOG on FACILITY.CATALOG_GUID = FACILITY_CATALOG.ID

至于后面的条件还是和前面一样加。我们可以想象一下这么做的问题:1、虽然用户只选择了站点这个条件,但是FACILITY和FACILITY_CATALOG进行了Join。2、如果用户只选择了设备编目,SQL语句就多了FACILITY和PROJECT、SITE的Join。当然啦,看到这里有人可能会说,我们用的框架没有这个问题或者你不会自己用if做判断啊。换框架没有必要,这里只是拿出一个典型的例子,相信就算换了框架,在开发过程中还是会遇到类似问题的。至于用if进行判断,同样也有麻烦,这个例子里的表比较少,写起判断没什么太大问题。关键是用户选择工程名称时你得加入FACILITY和PROJECT的Join,用户选择站点名称时你除了加入FACILITY和SITE的Join外,还必须先添加FACILITY和PROJECT的Join,否则就出错没商量。

      不知大家看到这个例子的特殊性没?本人见过一个项目组用这个框架的时候,一个SQL语句里一次性写了28个Join(自己汗一下先,怎么设计数据库的,虽说是该有不该有的都写了,也没有这么多吧)。当然这不排除数据库设计和框架的问题,其中还有一部分原因就是懒人多,表多条件多的时候谁都不喜欢一个if一个if拼SQL语句。说了这么多,总结起来就是“按需Join的问题”。如果能有一个工具能实现,一次性添加所需的所有东西,然后自动根据需要生成SQL语句,该多好(或者说方便多了,至少本人是这么认为的)?

      如果SQL语句进行分解。可以划分为显示的字段定义、表关联定义、条件定义、排序、分组等几个部分。因此,本人对SQL语句的各部分进行如下划分,并以以下术语命名:
      1、 Fields:输出字段的定义。
      2、 Joins:表关联定义。
      3、 Filters:查询条件定义。
      4、 GroupBys:分组定义。
      5、 Having:Having子句
      6、 Existis:Exists子句。
      7、 OrderBys:排序定义。
      8、 SubQuerys:子查询定义
      9、 UsedTables:查询中所使用的表。
      10、UsedJoins:查询中所使用的联结
      11、 QueryInfo:一条完整的SQL查询语句。
      12、 QueryBuilder:查询生成器。

因此SQL语句可以用如下形式表示:
select (Fileds) from (UsedTables | SubQuerys| UsedJoins] [where [Exists] Filters] [group by GroupBys] [having Having] [order by OrderBys]
注:黑体字表示SQL保留字。“()”表示必填项。“|”表示可在其中选择一项。“[]”表示可选项。

      经过分解后可以得出这样的结论,UsedTables中的表由所有的Fields、Exists、Filters、GroupBys、Having、OrderBys中所使用的表组成,SubQuerys也可以根据Alias从UsedTables判断是否使用。UsedJoins也可以用同样的方法来实现按需选取,复杂的地方是一个Join可能依赖另一个Join,就像例子里的FACILITY和SITE的那样。另外,Fields为空的时候必须转换为“*”,UsedJoins不为空时From部分用Join,UsedJoins为空时from部分则必须用UsedTables或SubQuerys来代替。

      暂时先到这,眼花脖子酸,下回给出对象图和实现思路。

posted @ 2008-04-23 09:39 陈鹏(偶是坏人) 阅读(1736) | 评论 (6)编辑

JSCFO当前版本号2.8。实现功能如下:
1、可同时对多个文件进行操作。
2、格式化代码。
3、合并文件。
4、变量名混淆(选择变量名混淆后会随机在if、for、while、dowhile中插入混淆用的判断)。
5、流程混淆。可选择打乱流程时进行分块的行数。(由于Javascript中没有goto,所以打乱代码后用for或while配合if或switch保证代码执行顺序。for或while和if或switch的配合有一定随机性,较难被找到规律。此功能会造成代码增大,不过没有办法)
6、字符串混淆。(目前方法较简单,后期考虑用压缩替代混淆)
7、数字混淆。(用数学表达式替代常数)
8、压缩。(简单的方法,Pack2的那种)
9、格式化和混淆时自动修正结尾没有加分号的情况。
10、修改正则表达式的写法,避免所有代码在同一行时发生错误。
界面如下:

试用版中ObfuscateOptions(混淆选项)不可设置,默认使用了变量混淆、流程混淆、字符串混淆、数字混淆;流程混淆时Lines(方块的行数)默认为1,压缩也不启用。Format Only(仅格式化)和Merge(合并)选项可自由设置。

使用方法:1、用File菜单下的Add和Remove菜单项增加删除文件。2、混淆选项可以不用选择,如果需要合并多个文件则钩选Merge,如果仅需要格式化代码请钩选Format Only。3、点击Obfuscate菜单下的Go进行混淆。如果Output Folder(输出目录)中有与源文件同名的文件,则在混淆后的文件名前加“Obfuscated_”。4、双击Files(文件列表)中的项可以在新窗口中显示所选择的JS文件格式化后的代码。

混淆前的代码:

var x = 0;
var z = false;

function Test()
{
    
for(var i=0; i<x; i++)
    {
        
if(z)
        {
            
var s = "Today's date is: ";
            
            
var d = new Date();
            s 
+= (d.getMonth() + 1+ "/";            //Get month
            s += d.getDate() + "/";                   //Get day
            s += d.getYear();

            alert(i
+ ":" + s);
        }
    }
}

= 10;
= true;
Test();

混淆后的代码(未压缩):

var $_A, x, z, $_E;
function Test()
{
    
for(var i = ((0x36 * 0x0+ 0x0); i < x; i++)
    {
        
if(z)
        {
            
var s, d, $_D;

            $_D 
= 0;
            
for(var $_D = 5; $_D >= 0; $_D--)
            {
                
if($_D == ((0x22 * 0x3- 0x66))
                {
                    alert((i 
+ $_A("%3B")) + s);
                }
                
if($_D == ((0x4f * 0x3- 0xec))
                {
                    s 
+= d.getYear();
                }
                
if($_D == ((0x3 * 0x3- 0x4))
                {
                    s 
= $_A("e%C3%D3%C5%DA%A0%9A%93%84%C5%D5%D9%85%89%DC%ADZ");
                }
                
if($_D == ((0x42 * 0x7- 0x1cc))
                {
                    s 
+= (d.getDate() + $_A("0"));
                }
                
if($_D == ((0x26 * 0x2- 0x49))
                {
                    s 
+= ((d.getMonth() + ((0x8 * 0x2- 0xf)) + $_A("0"));
                }
                
if($_D == ((0x1d * 0x7- 0xc7))
                {
                    d 
= new Date();
                }
            }
        }
    }
}
$_A 
= function ($_B)
{
    
var $_C;
    $_B 
= unescape($_B);
    $_C 
= String.fromCharCode($_B.charCodeAt(0- $_B.length);
    
for(var i = 1; i < $_B.length; i++)
    {
        $_C 
+= String.fromCharCode($_B.charCodeAt(i) - $_C.charCodeAt(i - 1));
    }
    
return $_C;
};

$_E 
= 5;
while($_E > 0)
{
    $_E
--;
    
if($_E == ((0x3a * 0x7- 0x193))
    {
        z 
= false;
    }
    
if($_E == ((0x30 * 0x0+ 0x1))
    {
        z 
= true;
    }
    
if($_E == ((0x0 * 0x2+ 0x0))
    {
        Test();
    }
    
if($_E == ((0x1e * 0x3- 0x56))
    {
        x 
= ((0x27 * 0x5- 0xc3);
    }
    
if($_E == ((0x26 * 0x2- 0x4a))
    {
        x 
= ((0x55 * 0x1- 0x4b);
    }
}

压缩后的代码如下:

eval(function(e,d){e=e.replace(new RegExp('\\b\\w+\\b','g'), function($0){return d[$0]});return e;}('0 $1=2($3){$3=4($3);0 $5=6.7($3.8(9)-$3.10);11(0 12=13;12<$3.10;12++){$5+= 6.7($3.8(12)-$5.8(12-13));}14 $5;};0 $15,$16;2 17(){11(0 12 = (18*19-20);(12 < $15) && !(21.$22>23);12++){24($16){0 $25,$26;$25 = $1(\"27%28%29%30%31%32%33%34%35%30%36%37%38%39%40%41\");$26 = 42 43();$25 += (($26.44() + (45*18-46)) + $1(\"9\"));$25 += ($26.47() + $1(\"9\"));$25 += $26.48();49(((12 + $1(\"%50\")) + $25));}}}$15 = (51*52-53);$16 = 54;$15=(55*18-56);$16=57;17();''var|_A|function|_B|unescape|_C|String|fromCharCode|charCodeAt|0|length|for|i|1|return|_D|_E|Test|0x2|0x4|0x8|this|_F|2|if|_G|_H|e|C3|D3|C5|DA|A0|9A|93|84|D5|D9|85|89|DC|ADZ|new|Date|getMonth|0x4b|0x95|getDate|getYear|alert|3B|0x52|0x3|0xf6|false|0x12|0x1a|true'.split('|')));

目前的流程混淆利用while或for配合if或switch控制打乱后代码的正常执行顺序,希望有朋友能提出更好的建议。字符串的加密也让人感到头疼。
混淆后的代码较原有代码增大不少,主要原因是针对每一行代码都进行了打乱并且没有进行压缩处理。进行压缩处理之后,还是可以接受的。

后期目标如下:
1、支持包含<Script language="javascript"></script>标记的文件。(暂定为此标记)
2、用压缩算法替代现在那个简单的字符串混淆方法。
3、尝试寻找新的流程混淆方法。
4、考虑是否加入函数名混淆。(个人目前认为函数名混淆的意义不大)
5、加入混淆排除选项。
6、考察是否有更高效的压缩算法,以替代Pack2目前的方法。

PS:
之前版本有用Themida加壳,发现很多朋友用ESET,故不用Themida,已更新。请想试用的朋友放心,绝无病毒。
至于有人说我不放源码的问题,这个似乎没有规定吧。我这个还只是给大家试用,并没有说要收钱干啥的。所以对源码有意见的请自己保留吧
准备开始新版本的工作,旧版本暂停下载。

posted @ 2008-04-23 03:20 陈鹏(偶是坏人) 阅读(1780) | 评论 (20)编辑