随笔-5  评论-209  文章-2  trackbacks-8

EES 框架 BLL层代码组织与介绍

       BLL层,我个人感觉是与通用的NH/IB OR映射差异比较大的地方,处于承上启下的位置。

       承上:可以与数据库打交道,起到了DAL的作用。

       启下:可以与BP层/Stub层/或客户端直接打交道,作为其服务层。

public class UserImp<T> : BLService<T>
    where T : EESObject, new ()
{

        [Operation(ScopeOption.Disabled)]
        public virtual T FindById(String code)
        {
            return base.FindId(code);
        }
        [Operation(ScopeOption.Disabled)]
        public virtual DataCollection<T> FindByName(string name)
        {
            Where clause = new Where();
            clause.Add("Name", name);
            return base.Find(clause);
        }
       

        [Action("保存", "保存")]
        [Operation(ScopeOption.Required)]
        public override T Save(T t)
        {
            return base.Save(t);
        }

       BLService<T> 为业务层的基类,主要提供增删改查的功能。默认状态下,基类的服务是不公开的,需要在此类里面公开。

       Operation为事务自定义属性,通常在此处添加,也可以在配置文件里添加。

       查询,也是此OR的一个特色,对于客户端和服务端的处理雷同,但不相同,服务器端可以使用 WhereEx ,支持拼接字符串和其他等特殊处理。在处理自定义查询的时候非常方便。

       Action自定义属性,为动作标注,在生成Controller的时候,会自动生成。

[EESBO("User")]
public class UserService : UserImp<User>
{   

    [Operation(ScopeOption.Required)]
    public virtual EESContext Login(string userId, string salt)
    {

         ………

    }

    [Operation(ScopeOption.Required)]
    [Action("密码复位")]
    public virtual User ResetPwd(User user)  

  {

         ………

    }

}

UserService 为常用编码的类,UserImp主要为自动生成的类,业务逻辑通常放在UserService类里面。

EESBO自定义属性标注此类为服务类,在生成代理/服务配置的时候,会自动生成配置文件和代理类。

其他的与UserImp类似。

一直在考虑,是不是要把Linq加入进去,没有决定下来。

 

        公开的类必须添加 virtual ,使用的时候,可以用:ProxyFactory.getProxy<UserService>() 或Factory.New<UserService>,通常在服务器端用 Factory.New<UserService>()方式,在客户端用 ProxyFactory.getProxy<UserService>() 方式调用。

        示例代码:

        main()

        {

        EES.Common.Config.Configuration.Root = “……”;

        User user=Factory.New<User>();

        user.Code=”123456”;

       

        UserService srv=Factory.New<UserService>();

        srv.Save(user);

        }

       

        此处没有太多的处理加载的地方,系统会自动处理配置文件的加载,基于声明式事务的处理,对于多数据源和层次操作,则会一层一层的处理。

        如果需要通过http进行远程调用,服务器端的UserService不需要作任何的改变,只需要加入到IIS里面,并添加些配置文件,则可通过http实现远程RPC调用,客户端代码不需要作改变,也是更改一下,添加一个自动生成的代理类则可。具体如何修改和处理,后面会继续介绍

      

        不知道大家对于此种ORM映射的BLL处理有什么想法,请给些建议

        在此谢谢了

posted on 2010-08-30 15:03 光影传说 阅读(1670) 评论(10) 编辑 收藏

评论:
#1楼 2010-08-30 15:23 | cdboy      
感觉有点像clsa
 回复 引用 查看   
#2楼 2010-08-30 16:12 | 路过秋天      
ORM的用法还是差不了多少的,和我去年写的框架相近,看用法:
 UserListBean entity = new UserListBean();
            entity.GetFrom(tbxUser_Name);
            entity.GetFrom(tbxFull_Name);
            entity.GetFrom(ddlUser_Type);
            entity.GetFrom(tbxPassword);
            entity.GetFrom(tbxEmail);
            entity.GetFrom(tbxCreateUser, CurrentUser.User_Name);
            entity.GetFrom(chbEnabled);
            entity.GetFrom(tbxRemark);
            if (GetID == 0)
            {
                entity.GetFrom(tbxPassword);
                if (Factory<UserListBean>.Instance.Add(entity))
                {
                    LogWrite.Write(LogModule.用户管理, LogType.增加, string.Format("添加用户[编号={0}]", entity.ID));
                   
                }
            }
            else
            {
                entity.GetFrom(lblID);
                if (Factory<UserListBean>.Instance.Update(entity))
                {
                    LogWrite.Write(LogModule.用户管理, LogType.编辑, string.Format("更新用户[编号={0}]", entity.ID));
                   
                }
            }

增加一个GetFrom与SetTo之后,代码质量有了质的飞跃,你也赶紧试试吧。

 回复 引用 查看   
#3楼[楼主] 2010-08-30 17:20 | 光影传说      
@cdboy
非常感谢,从你那里我才知道了clsa。下午看了一下clsa,感觉在思想上与clsa有很多相似的地方,但是处理方式上,相差还是很多的。比如,级联方式处理机制方面,相差就非常大,但是目标是一致的。
在对象模型这一块也有一定的不同:
[Serializable]
[Csla.Server.ObjectFactory("DataAccess.OrderFactory, DataAccess")]
public class Order : BusinessBase<Order>
{
public static PropertyInfo<int> IdProperty = RegisterProperty<int>(p => p.Id);
public int Id
{
get { return GetProperty(IdProperty); }
private set { SetProperty(IdProperty, value); }
}

public static PropertyInfo<string> CustomerNameProperty = RegisterProperty<string>(p => p.CustomerName);
public string CustomerName
{
get { return GetProperty(CustomerNameProperty); }
set { SetProperty(CustomerNameProperty, value); }
}

public static PropertyInfo<LineItems> LineItemsProperty = RegisterProperty<LineItems>(p => p.LineItems, RelationshipTypes.LazyLoad);
public LineItems LineItems
{
get
{
if (!FieldManager.FieldExists(LineItemsProperty))
LoadProperty(LineItemsProperty, LineItems.NewList());
return GetProperty(LineItemsProperty);
}
}


protected override void AddBusinessRules()
{
BusinessRules.AddRule(new Csla.Rules.CommonRules.Required(CustomerNameProperty));
}

private Order()
{ /* require use of factory methods */ }

public static Order NewOrder()
{
return DataPortal.Create<Order>();
}

public override Order Save()
{
return base.Save();
}
}

从他们的Demo代码上面可以看的出来,他们用的是充血模型,而我用的是贫血模型,这种模型在处理服务器与客户端数据类型统一的时候,很难做。当然,这种模型也有自己的优点,在开始的框架里面也用过。
public static PropertyInfo<string> CustomerNameProperty = RegisterProperty<string>(p => p.CustomerName);
public string CustomerName
{
get { return GetProperty(CustomerNameProperty); }
set { SetProperty(CustomerNameProperty, value); }
}
这种结构,对于后续的升级不方便,在上一个版本的框架里用过类似的方案,在当前版本的框架里面,已经去掉了。
不过,在权限处理方面,还是非常需要好好学习的,这一块我的框架里面,还没有处理。
我只是花了不太长的时间看了看,可能还有许多关键点我没有理解,有时间我再好好的看看
谢谢!

 回复 引用 查看   
#4楼[楼主] 2010-08-30 17:27 | 光影传说      
@路过秋天
兄弟的做法耦合度太高了,对于处理分布式的时候不方便,可以考虑用
Util.GetFrom/SetTo 这样的方式,或许会更好一点,另外,日志可以不需要写在代码里面,用配置的方式,可能更灵活些。

 回复 引用 查看   
#5楼 2010-08-30 17:28 | henry      
从楼主的想法来看,做这些继承约束实现的目的就是横向功能处理..说实话摆脱继承这个约束对使用者来说更方便简单.
对于基类封装简单化的功能其实起得作用不大,特别在数据访问方面.
public virtual T FindById(String code)
{
return base.FindId(code);
}

public virtual User FindById(String code)
{
return DB.FindId<User>(code);
}
没有多大差别,但前者需要一个基类支持用起来就不太爽了.

 回复 引用 查看   
#6楼[楼主] 2010-08-30 17:53 | 光影传说      
@henry
接受批评,很快就加入这个类在里面。其实,底层本来就有这样的一个类,只是没有开放出来。从最终达到的目的上,是完全一致的。

我只所以这样做,就是为了少写几行代码罢,基类里面还有此其他的函数,可以直接使用,在做相关处理的时候,就不需要关心这个函数是DB的还是自己写的了,只需要关心这个UserService这个类,如果不是这样,则需要把DB里面的很多常用函数再重写一遍,比较麻烦;如果在其他相关类里面直接用DB的函数,也可以,不过好像有点破坏了封装。

请指教

 回复 引用 查看   
#7楼 2010-08-30 18:11 | henry      
@光影传说
DB做的事情就是专于数据处理,他是提供给不同逻辑调用的.如果他本身不能很好的工作而是依赖于某些逻辑的设计,那这个设计是不是有点不合理呢?
我感觉BLService<T>是应该封装一些逻辑上的东西或辅助的东西如代理等,如果DB本身操作已经够方便了,BLService<T>是否有必要封装DB的工作而让他变得臃肿.
BLService<T>这个T让人搞不懂,在实现应用中BLService不紧紧针对一个实体,如user,她有可能还有account,setting等信息.那这个时候BLService<T>似乎难以表达,难不成还要起个BLService<account>?这显然是不可能的account是否存在决定于user.



 回复 引用 查看   
#8楼[楼主] 2010-08-30 21:10 | 光影传说      
@henry
首先,这个框架的设计思想就是基于泛形的SOA或面向对象的框架。
面向对象主要的思想是封装和继承。
BLService<T>主要是封闭了与数据库相关的常用操作和业务对象的常用处理模型,也就是些辅助的东东。如果不是与数据库相关的业务,完全可以不必从BLService<T>继承。
兄台所说的BLService不仅仅针对一个实体,可能还有account和setting 之类等信息,完全正确,这个框架里的数据本身就是层次型的,是完整意义上的领域模型。
User与account可以是一对多的关系,或者说聚合关系
类似
public class User
{
DataCollection<account> _accountCollection;
public DataCollection<account> AccountCollection
{
get{return _accountCollection;}
set{_accountCollection=value;}
}
}
account 是属于User,但,account也是独立的,只是依赖User而已。
account 同样应该具备自己的操作,如果在BLService<User>里面直接操作account,基本上是违反了面向对象的设计理念,会造成复杂逻辑的难以维护。

我的框架与UML通常可以作映射的,通过分析通常能够把UML图映射到编码接口上去,框架的背后有一套完整的分析与设计的思想支持。如果画序列图,则从序列图上能够完整的反映出来。基本上可以做到分析设计与编码的分离,程序员A写的代码与B写的代码一样。

分析设计如何与框架进行映射的,在后面,我会陆续介绍的
我的理解可能有偏差,请指教

 回复 引用 查看   
#9楼 2010-08-30 23:16 | henry      
@光影传说
首先,这个框架的设计思想就是基于泛形的SOA或面向对象的框架。
面向对象主要的思想是封装和继承...

也是许是,我认为对使用者来说简单越好,如果不能继承就能方便调那就更简单了..不过设计这东西因人而异..我喜欢的方法不代表其他人喜欢,以上紧是我个人的观点.

 回复 引用 查看   
#10楼[楼主] 2010-08-31 18:24 | 光影传说      
@henry
同理,我们可能是设计方式上有所差异,不能说谁对谁错
每个人都有自己的理解,最终目标是解决问题

 回复 引用 查看   
昵称:光影传说
园龄:6年10个月
粉丝:2
关注:0
<2010年8月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

搜索

 
 

常用链接

我的标签

随笔档案

文章分类

相册

最新评论