惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
Arctic Wolf
T
The Blog of Author Tim Ferriss
月光博客
月光博客
Recent Announcements
Recent Announcements
V
V2EX
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 三生石上(FineUI控件)
P
Proofpoint News Feed
The Register - Security
The Register - Security
博客园 - 叶小钗
博客园 - Franky
The Cloudflare Blog
雷峰网
雷峰网
罗磊的独立博客
M
MIT News - Artificial intelligence
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 【当耐特】
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
爱范儿
爱范儿
博客园 - 司徒正美
Recorded Future
Recorded Future
酷 壳 – CoolShell
酷 壳 – CoolShell
Google DeepMind News
Google DeepMind News
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
F
Full Disclosure
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
B
Blog
大猫的无限游戏
大猫的无限游戏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
腾讯CDC
WordPress大学
WordPress大学
小众软件
小众软件
K
Kaspersky official blog
Attack and Defense Labs
Attack and Defense Labs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Forbes - Security
Forbes - Security
aimingoo的专栏
aimingoo的专栏
IT之家
IT之家
The Last Watchdog
The Last Watchdog
N
News and Events Feed by Topic
B
Blog RSS Feed
S
Security @ Cisco Blogs
美团技术团队
量子位
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cloudbric
Cloudbric
Hacker News - Newest:
Hacker News - Newest: "LLM"

博客园 - 成为-行动-拥有(BeDoHave)

我的MIS快速开发框架集成参考 选择一个框架的权衡建议 简单为美的IT开发尝试 请跟我来(完)--使用Ext及其llano的注意事项 请跟我来--使用Ext+llano快速搞定CRUD 请跟我来--Ext数据应用开发的几板斧 请跟我来--使用Ext搞个原型 请跟我来(EXT2.0+llano实践) 2007年的最后的几笔 用NBear和QPG分布式框架改善生活 - 成为-行动-拥有(BeDoHave) - 博客园 风继续吹----对一些ORM框架的使用心得(2) 欢迎新成员加入! QPG分布框架1.1.1 需求看板单机版可以使用了 QPG加速器的使用 QPG分布框架V1.1 BETA2说明 是"渔"非"鱼"--QPG分布处理框架V1.1(Beta1)简介 实践篇(4)—需求看板解析 实践篇(3)--关于事务处理的一点细节
冷眼程序人生----对一些ORM框架的使用心得
成为-行动-拥有(BeDoHave) · 2006-04-06 · via 博客园 - 成为-行动-拥有(BeDoHave)

序:
    信不信由你:
        谁都可以写出机器能执行的代码,但不是谁都写得出其他程序员也看得懂的代码.(流醒鱼的感慨)
        任何一个工具都很难被使用者真正掌握,工具越强大,配置越复杂,复杂性从code变成config

    有时自己觉得真的不年轻了,怎么也多少有些唠叨了?

一)问题描述
最近一直在尝试几个ORM框架,我感觉他们都不错的,只要你真正掌握,对付一般小Mis系统应该都不成问题.

几乎每个工具都有现成的例子,但是这些例子往往过于简单.请看Hibernate的例子:
Public class Blog
{
...
public IList Posts;
}

Public class Post
{
...
public Blog owner;
}
这个例子本来也没有什么问题,只是很多人依葫芦画瓢就搞起了商业系统,看到他们的一些代码,实在是能预感到维护阶段的一幕幕。

二)避免问题的一点经验
经过自己看别人的程序感触,我把这些要点记下来,大约如下:
1) 逻辑变化和扩展要对实体类关闭频繁修改
   比如有个User类,那我们做人事系统时可能有TimeCard;而我们做项目管理系统时又可能有Task等
2) 实体和逻辑类必须在完全没有数据库支持的情况下测试通过,证明自己的清白
   当数据库操作一上来后,会发生大量异常,千万不要把宝贵的时间放在联调上,分布式跟踪代价“高,实在是高”!

所以我通常用下面的图来提醒自己:

            业务实体、业务逻辑
---------------实体关系------------
              数据操作

可以看到实体关系处在一个灰色地带,放到那里可以根据具体情况决定

三)一个较为清晰的实例
为了突出思路和要点,下面将采用Teddy的ORM框架来解释,其他的类似,主要调整一下数据访问层。


3.1)业务背景
  每个应用都重复着组、用户的这些逻辑,用这个例子大家一定不会陌生
  规则1:一个组可以再包含下面的组,但是系统只有一个最顶层的组
  规则2:一个组可能有多个用户(也可能没有)
  规则3:一个用户至少一个组

下面的例子主要针对规则2。

3.2)代码演示
首先定义数据实体
注意,vUsersOfGroup是一个视图,只是改进效率,原则上不应该出现在实体类中
为了能够表达规则2,建立下面的实体关系类

using System;
using System.Data;
using Ilungasoft.Framework.Common;
namespace Teddy.ORM.Test
{
    
public abstract class Entity
    
{
    
        
public interface Group : IEntity
        
{
            
int ID getset; }
            
string Title getset; }
            
string Description getset; }
            System.DateTime CreateTime 
getset; }
            
int ParentID getset; }
        }


       

        
public interface User : IEntity
        
{
            
int ID getset; }
            
string Name getset; }
            
bool Gender getset; }
            
double Salary getset; }
        }

        
public interface vUsersOfGroup : IEntity
        
{
            
int ID getset; }
            
string Name getset; }
            
bool Gender getset; }
            
double Salary getset; }
            
int GroupID getset; }
        }

    }

}

public  class MemberShip
    
{
        
public Entity.Group Group;
        
public Entity.User Administrator;
        
public Entity.User[] Members;


        
public MemberShip()
        
{
            
        }

        
public MemberShip(Entity.Group g,Entity.User u,Entity.User[] members)
        
{
            Group 
= g;
            Administrator 
= u;
            Members 
= members;

        }

    
      
    }

关系数据的操作类也比较简单

using System;
using System.Data;

using Ilungasoft.Framework.Common;
using Ilungasoft.Framework.Data.Facade;
using Teddy.ORM;
namespace Teddy.ORM.Test
{
    
public  class MemberShipLoader
    
{
        
private Gateway _gw;

        
public MemberShipLoader(Gateway gw)
        
{
            _gw 
= gw;
        }

      
        
// todo 如果框架中使用反射自动做这类事就好了!
        public Entity.User clone(Entity.vUsersOfGroup vUser)
        
{
            Entity.User u 
= EntityFactory<Entity.User>.CreateObject();
            u.ID 
= vUser.ID;
            u.Name 
= vUser.Name;
            u.Salary 
= vUser.Salary;
            u.Gender 
= vUser.Gender;
            
return u;
        }

        
public MemberShip getMemberShip(Entity.Group group)
        
{
            Entity.vUsersOfGroup[] temp_users 
= _gw.Select<Entity.vUsersOfGroup>("GroupID=" + group.ID);
            Entity.User[] us 
= new Entity.User[temp_users.Length];
            
int i = 0;
            
foreach (Entity.vUsersOfGroup t in temp_users)
               us[i
++= clone(t);
            
return new MemberShip(group, us[0], us);

        }


    }

}

最后就是证明自己的清白了:

using System;
using System.Data;
using System.Collections;
using NUnit.Framework;
using Ilungasoft.Framework.Common;
using Ilungasoft.Framework.Data;
using Ilungasoft.Framework.Data.Facade;
using Ilungasoft.Framework.Data.MsAccess;
using Teddy.ORM;
    [TestFixture]
    
public class Tester {
        
        [SetUp]
        
public void Init() {
                
        }

        [TearDown]
        
public void Finish() {
            
        }

        
       
        [Test]
        
public void testSimpleDataAccess()
        
{

            
string connstr = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\SORM\App_Data\TestRelation.mdb";
         
            Database db 
= new Database(new AccessDbProvider(connstr));
            Gateway gw 
= new Gateway(db);
            MemberShipLoader msl 
= new MemberShipLoader(gw);

            Entity.Group g 
= EntityFactory<Entity.Group>.CreateObject();
            g.ID 
= 1;  g.Description ="Demo 公司";
         
            MemberShip ms 
= msl.getMemberShip(g);
            Console.WriteLine(
"Group:" + ms.Group.Description);
            Console.WriteLine(
"Administrator:"+ms.Administrator.Name);
            Console.WriteLine(
"====Members======");
            Assert.AreEqual(
3, ms.Members.Length);
            
foreach (Entity.User u in ms.Members) Console.WriteLine(u.Name);
        }

       }

我机器上的结果如下:
Group:Demo 公司
Administrator:Alex
====Members======
Alex
cxiong
yxiuquan

四)小结
  4.1 先梳理出清晰的概念,然后再编码,选择合适的工具。
  4.2 因为时间和篇幅,我并没有按照自己的要求在没有数据联入时进行单元测试,因为这个例子太过于简单,所以万事不要绝对。
  4.3 Teddy的框架如果能够方便吧Entity导出到XML今后就更加实用,不知何时能看到。
  4.4 Teddy的框架能加上MySQL和Oracle的DbProvider就会更加实用了。