现在的项目用了简单的三层结构,继续学习ing......

解决方案 »

  1.   

    VS中有一个非常的例子Duwamish 7.0绝对对你有启发,在安装目录下的Enterprise Samples目录中,安装做的也简单
      

  2.   

    表现层如果哪Asp.net 为开发工具,本身就一个不错的表现层,他使用MVC 模式
    如WebForm.aspx是个View WebForm.aspx.cs是个Control,而Module就有业务层的组件实现
    商业逻辑层
    存放各种业务组件,这里很有弹性,以后再说,因为如果是N层
    这里面有很多,如业务外观、业务实体,业务规则,还有数据访问组件,数据库
    不用说了吧,Sqlserver MySql都可以实现
      

  3.   

    推荐:Desing and Implemetation Guides for Web Clients
    Microsoft的文章,www.only4gurus.com上有, and much more...
    :-)
      

  4.   

    ok马上来
    例如:(跟公司上上下下说了无数遍的事列)
    你有个一个用户,一个地区,一个部门,三个数据表,他们互相的组合可以得到你需要的
    信息。你现在需要得到,一个用户类,你可以通过 “用户.部门”得到部门对象,而通过"用户.部门.office[2]“得到那个部门第三个科室的对象。那么这个类就是一个业务外观拉业务外观就是你在WebForm.aspx.cs文件想操作的对象啦!
      

  5.   

    当然业务外观可以是个对象,也可以是一组对象,也可以是个 DataSet,主要看你的用途
    拉!
    如果你想增加一个用户,你操作的想当然是个对象啦,只要在WebForm.aspx.cs 方法就可以啦
    如:
       UserManage manage=new UserManage(ConnectionString)//UserManage是个业务规则组件
       ///建立新用户
       User newUser=new User(loginid.text,.....);
       newUser.Department=new Depatrent(Information.......
       newUser.Location=new Location(......);
       ///然后增加
       manager.Add(newUser)
       //增加完成拉
    做Asp.net页面的人,不用理会怎样实现,Sql怎样写,数据库是什么,只要接口没有写错就可以啦
      
      

  6.   

    微软的IBuySpy与Duwamish 7.0怎么都没有比如添加商品,修改商品等后台管理程序呀
      

  7.   

    上面那个UserManager写错了,不是业务规则其实也是个业务外观,手快快,写错了
      

  8.   

    在duwamish7.BusinessFacade.CustomerSystem里,你看到那个就商业外观
    它通过CreateCustomer(String,byte[],string,string....)那个增加一个Customer
    我那个和他的不同是,我用类去维护接口,而Duwamish用字段维护,
    用类去维护好处是,如过字段一旦改变(增加OR减少),只需要维护
    业务对象类,和Add方法就可以拉,而不需要维护调用的地方(如果有100个,那你
    得一个一个改!)
      

  9.   

    听ing fantasylu(fantasy) 讲课
      

  10.   

    我曾经在微软的中国社区里看到过一篇文章,虽然讲的不是很深但是我想应该会有点帮助的
    http://www.microsoft.com/china/community/Column/93.mspx
      

  11.   

    不论3层还是5层,这些都是为了程序直接的松散耦合而服务的。如果你的分层没有达到松散耦合的效果那么也就没有什么实际的意义,但是分层使得代码更加清晰,容易理解。这种分层的思想可能源于MVC吧。其实分层种最难的就是业务逻辑层,也就是通常所说的中间层,中间层包括很多业务逻辑和业务对象,业务对象的数据又是由数据服务层提供的,业务逻辑可以作为一个单独的逻辑单元使用。这里有一个问题业务层里面应不应该包括SQL语句呢?如果包括那么业务层和数据层必然存在功能耦合数据库的变化使你不得不改变业务逻辑层的代码。如果使用存储存储过程这种耦合度可能会小一些但是还是存在的,我的意思就是这两者之间要怎么样才能实现真正的分离,也就是说你的业务层里面的逻辑和对象,要求一个接口,只要能满足这个接口要求的数据库服务对象就可以作为他的数据提供者,这个业务对象就可以消费这个数据库对象提供的数据。所以关键还是接口定义的问题,又回到了设计模式,经典的一句话“针对接口编程,而不是针对实现编程”。
    上面是我的个人意见如有不妥请大家一起讨论。
      

  12.   

    cuike519(studing sps(修练中...)) ,你好同意我觉得3层,不能很好地分离业务逻辑,所以我一直都使用n曾架构.因为3层的或分,对于我面对现有大部分的需求,都会造成混乱.所以n层出现是在增加现有开发成本,但可以大部分减少
    维护曾本的方法,而且可以用增加同意,这个,但是,一般公开到Aspx.cs文件中使用的都是业务外观,所以
    我觉得 业务外观,业务规则,业务实体,也是把商业逻辑造成MVC。是他们更好管理我比较反对SQL在逻辑层出现,因为这些SQL很难管理(但是很容易写)
    (但是对于复杂查询保留意见,没有任何EntityClass能完美解决这个问题)
    我认为增加DAL(Data Access Layer)更好解决这个统一的问题,而我现在使用Grove也可以
    解决这个问题,张雪峰的 实战 .Net 数据访问层_1.2 里面提到的方法也很好而接口定义的问题,我很同意这个,因为接口就是标准,继承接口,就是实现了相应的逻辑上面是我的个人意见如有不妥请大家一起讨论(借来用用)
      

  13.   

    具体项目具体分析:比如duwamish7和petshop,两个实体层不同的实现方式。
      

  14.   

    回到昨天的话题
    n个业务实体(n>=1) 通过 业务规则,生成业务外观(可能是DataSet DataReader,业务对象集或单个业务对象),那么他们就是一个MVC架构,
    而业务实体是通过DAL层得到数据的,大部分的业务实体是一个业务实体对应一个数据表(好像是petshop的方法),数据实体是商业逻辑与DAL之间的交互载体,而业务外观是UI(user interface)与商业逻辑层的交互载体怎样去实现是:我觉得是我们应该讨论的话题
      

  15.   

    回复人: zhongkeruanjian(编程亮子) ( ) 信誉:84  2004-05-13 11:18:00  得分:0 
     
     
      不是所有的项目都要用接口,也不是所有的项目都要实体
    ----------------------------------------------------------------------------------
    我觉得
    只要你是做n层,所有的业务对象,都要实现实体(duwamish7是DataSet,petshop是Arraylist),
    接口是标准,实现接口是统一业务逻辑,当然有例外,例如没有标准的时候
      
     
      

  16.   

    听:fantasy 讲课!多成结构,叫我说出来怎么实现的,是什么个原理,这个我办不到!但是我明白那个意思怎么实现。我写文档写的少,做开发都多了点,呵呵建议大家看看MsPetShop,(Micorosft提供的Asp.Net范例)那里面就是一个三成架构来实现的!我当初学习Asp.Net就是重那个学起的,收益非浅!谁需要原代码(MsPetShop),联系我:qq---4533705 Email:[email protected]
      

  17.   

    另外看看:kaneboy 用三层架构来实现的的个例子。。转:         ASP.NET终于可以让Web开发人员从ASP的面条代码中脱身出来,以全新的方式来构建Web站点,就像Windows Application一样,我们同样可以用面向对象的、多层的方式来组织和构建Web Application。         下面给出的是一个功能非常简单的留言本程序,旨在揭示ASP.NET强大的能力和全新的开发方式。如果只相对留言本程序本身而言,大家可能怀疑用这么多的气力实现如此简单的程序是否值得,但我说过,例子只是用来说明问题和描述解决方案。其实我认为,从维护和扩充的角度来说,即使再简单的程序,从一开始就进行良好的设计也是非常值得的。          留言本采用多层的方式来构建,下面的介绍为了方便大家理解,并未按照层次的顺序介绍:         一、数据实体(CMessageData类)         CMessageData派生自DataSet,用来维护留言数据,在构造函数中,调用CreateDataTables()来增加一个用来保存留言数据的DataTable,并加到自身的DataTable集合中。静态属性TableMapping用来描述这个DataTable的DataColumn和数据库中物理字段的映射关系,数据访问层将使用这个属性来填充数据进CMessageData对象中。         public class CMessageData : DataSet {        public CMessageData() {            this.CreateDataTables();        }         public static DataTableMapping TableMapping {            get {                DataTableMapping result = new DataTableMapping("t_gbook_postinfo", "MessageTable");                result.ColumnMappings.Add("id", "Id");                result.ColumnMappings.Add("last_reply_time", "LastReplyTime");                //…..                return result;            }        }         private void CreateDataTables() {            DataTable dt = new DataTable("MessageTable");            dt.Columns.Add("Id", typeof(Int32));            dt.Columns.Add("LastReplyTime", typeof(DateTime));            // …..             dt.Columns["Id"].AutoIncrement = true;            dt.Columns["Id"].AutoIncrementSeed = 0;            dt.Columns["Id"].AutoIncrementStep = -1;            dt.PrimaryKey = new DataColumn[] {dt.Columns["Id"]};             this.Tables.Add(dt);        }    AddedNewRow属性返回一个新增进数据表的、空的DataRow,用于给逻辑层填充。FillDataFormDataBase()的两个重载调用数据访问层的相应方法来填充一个新的CMessageData对象并返回。UpdateToDatabase用于讲自身的数据更改更新回数据库。public DataRow AddedNewRow()…public static CMessageData FillDataFromDatabase(Int32 startRecord, Int32 maxRecord)…public static CMessageData FillDataFromDatabase(Int32 id)…public void UpdateToDatabase()…         二、数据访问层(CDataAccess类)负责连接数据库,进行SIUD(Select,Insert,Update,Delete)操作。数据连接信息放在AppParameters.xml文件中。 FillMessageData()的两个重载创建新的CMessageData对象,填充数据,然后返回:public static CMessageData FillMessageData(Int32 startRecord, Int32 maxRecord)public static CMessageData FillMessageData(Int32 id) UpdateMessageData()把参数中的CMessageData对象所作出的更改更新回数据库:public static Int32 UpdateMessageData(CMessageData messageData) {            OleDbConnection conn = new OleDbConnection(CAppParameters.OleDbConnectionString);            OleDbCommand cmdSelect = new OleDbCommand("Select username,last_reply_time,guest_name,guest_email,guest_website_name,guest_website_url,guest_oicq,guest_ip,guest_post_time,guest_text,reply_data From t_gbook_postinfo", conn);             OleDbCommand cmdInsert = new OleDbCommand();            cmdInsert.Connection = conn;            cmdInsert.CommandText = "Insert Into t_gbook_postinfo (last_reply_time,guest_name,guest_email,guest_website_name,guest_website_url,guest_oicq,guest_ip,guest_post_time,guest_text,reply_data) Values (@last_reply_time,@guest_name,@guest_email,@guest_website_name,@guest_website_url,@guest_oicq,@guest_ip,@guest_post_time,@guest_text,@reply_data)";            cmdInsert.Parameters.Add("@last_reply_time", OleDbType.DBDate, 0, "last_reply_time");            cmdInsert.Parameters.Add("@guest_name", OleDbType.VarWChar, 255, "guest_name");            //…             OleDbCommand cmdUpdate = new OleDbCommand();            cmdUpdate.Connection = conn;            cmdUpdate.CommandText = "Update t_gbook_postinfo Set last_reply_time=@last_reply_time,guest_name=@guest_name,guest_email=@guest_email,guest_website_name=@guest_website_name,guest_website_url=@guest_website_url,guest_oicq=@guest_oicq,guest_ip=@guest_ip,guest_post_time=@guest_post_time,guest_text=@guest_text,reply_data=@reply_data Where (id=@Original_id)";            cmdUpdate.Parameters.Add("@last_reply_time", OleDbType.DBDate, 0, "last_reply_time");            cmdUpdate.Parameters.Add("@guest_name", OleDbType.VarWChar, 255, "guest_name");            //…             OleDbCommand cmdDelete = new OleDbCommand();            cmdDelete.Connection = conn;            cmdDelete.CommandText = @"Delete From t_gbook_postinfo where (id = @Original_id)";            cmdDelete.Parameters.Add("@Original_id", OleDbType.Integer, 0, "id").SourceVersion = DataRowVersion.Original;             OleDbDataAdapter ada = new OleDbDataAdapter(cmdSelect);            ada.InsertCommand = cmdInsert;            ada.UpdateCommand = cmdUpdate;            ada.DeleteCommand = cmdDelete;            ada.TableMappings.Add(CMessageData.TableMapping);                        return ada.Update(messageData, "t_gbook_postinfo");        }把数据访问层单独提取出来的好处就是其他层都不会直接和数据库打交道,如果我们把数据库从Access改成SqlServer只需要用一个新的CDataAccess类替换现在的即可。在源码中,就有一个使用了Odbc.Net实现的COdbcDataAccess,用这个替换掉CDataAccess不会对程序中其他部分产生任何影响,我们可以利用Odbc.Net的访问能力,把数据库改为Oracle、Forpro等。 三、逻辑层这个留言本的逻辑层很简单,由三个类组成,CMessage用来描述一条留言,CReply用来描述一条回复,CReplyCollection集合类用来描述多条回复。CMessage提供了一个重载的构造函数:public CMessage(DataRow row)我们可以用CMessageData中个一个DataRow的数据来初始化一个CMessage对象。public void FillDataRow(DataRow row)这个函数则把自身的数据填充进参数中的DataRow对象。我们用类似:GetMessage().FillDataRow(messageData.AddedNewRow())这样的代码就可以把一条新的留言内容新增到一个CMessageData对象中,其中GetMessage()是页面上收集用户填入的数据并返回一个CMessage的一个方法。public CReplyCollection Replys这个属性用来公开对自身这条留言的所有回复。 四、界面层 - 用户控件为了方便我们把一个CMessage对象和页面上显示出来的一条留言绑定在一起,把一个CReply对象与页面上显示出来的一条回复绑定在一起,我们制作两个UserControl。MessageBlock控件用来显示一条留言,它通过属性:public CMessage Message来对象公开CMessage接口,我们只需要把一个CMessage对象赋值给这个属性,就可以让这个控件显示CMessage对象所表示的留言的内容。ReplyBlock控件用来显示一条回复,同样通过属性:public CReply Reply来公开一个CReply类型的接口。在MessageBlock控件中,我们根据对应的CMessage对象的Replys属性中所包含的回复,通过LoadControl()方法来动态载入ReplyBlock控件,并放置在一个PlaceHolder类型的Web控件中。 五、界面层 - 页面现在页面的显示非常简单了,我们在主页面(default.aspx.cs)中创建一个CMessageData对象,填充数据,再用LoadControl()方法来载入MessageBlock控件来显示留言就可以了。CMessageData messageData = CMessageData.FillDataFromDatabase((iPage - 1) * iPageSize, iPageSize);for(Int32 i = 0; i < messageData.Count; ++i) {                MessageBlock msg = (MessageBlock)LoadControl("MessageBlock.ascx");                msg.Message = new CMessage(messageData.Tables["MessageTable"].Rows[i]);                hldMessage.Controls.Add(msg);}
      

  18.   

    其实我觉得petshop和dumiwish7的主要区别在于实现 DAL层的不同,也就是实体不同,一个是对DataSet,另外一个是ArrayList的对象集合,其他的划分原则是一样的,但是由于外观的不同,显示的方法也跟着改,然后输入输出也不同。
    也就是只不过他们是实现n层的架构的不同方法。
    在DAL中 一个把数据表看作对象,一个把数据表看作数据字段,他们要求的都是要
    实现DAL中,业务与数据库存储无关。
    而我更喜欢PetShop的实现方法,因为可以在建模时,不考虑数据库。 这个很重要,
    因为我觉得我们做开发的,很容易变成面向数据库开发,
    一旦作系统分析,我们就很容易想到
       哈!这个用个Select 那里用个Update那不就行了嘛!
       (以前一位前辈对我说:数据库只是保存对象状态的众多工具中的一个。)
    但是数据库只是保存数据,但不能保存我们的商业对象(我这里指的是商业对象包含的概念)
    如果商业逻辑有Sql ,维护时候,你只看到数据库那数据,但不知道那些数据是拿来干什么的,数据是属于那个现实中的对象的。如果代码能反映程序的逻辑,不是很好吗?
    而petshop较好(但不是最好)解决这个问题,应为他真的把数据库当作保存对象状态的
    一个容器。但是由于,数据库是关系数据库,正如上面所说,office里面有多个User,department里面又包括多个office, 一个Company里面又有多个department,这样的关系,那么我想得到
    一个User属于那个地区的,我作为User Interface的开发人员,我就想   User user=UserManager1.Search(Loginid)//一个通过登陆名得到User对象方法
       string LocaionName=User.office.department.Location.Name;//这样很直观阿
      但是在业务规则就要不能像Sql那样写个多表关联的SqL去得到那个对象,你必须
      向office 的业务实体得到office的属性(用外键关联),office实体向deptment实体要求得到  deptment对象,deptment又要向location得到到对象。性能肯定比Sql多表关联低得多
    而且我们在页面上DataBind以上所有字段,你能走得通吗!所以在Java对数据库写的时候用EntityClass (CMP),而读的时候用 DAO.然后通过商业规则组装这些对象或data;而Grove,(.net中的一个ORM类),就集成了CMP的读写方法,和提供一个建立关联表查询的工具,这个工具生成后是个关联类,用起来也是个对象。我现在就用它,看看《程序员》
    有它的介绍。
      

  19.   

    我觉得比较难决策的是:
    外观的数据集(DataSet) 对象集(很多User对象),单个对象,怎样互相转换.
    你们有什么好方法
      

  20.   

    给你们一个不用实体的例子:比如一个查询系统:此系统无须数据管理,只需取数据展现。我想就很难用实体层,
    先假定定义了实体:用户,公司,部门,。
    这样的实体有什么用呢? 我取用户数据的时候经常要把此用户的公司,部门信息取出来,那你不得不把用户实体填充,把用户所属公司的实体填充,用户所属部门的信息填充。麻烦!
    不如简单地从数据访问层把数据库的数据用DATATALBE返回,不过要在注释中写明到底返回了哪些字段。我个人认为在数据管理(数据插入,修改)系统中用到实体才合算。
      

  21.   

    特别是在信息与界面层的数据绑定控件链接时,如果你定义了多个实体,还不得不又要重新把这些实体归结到一个datatable或arraylist中。呵呵,讽刺--从数据访问层返回的多个实体,现在又不得不重新合在一起。
      

  22.   

    zhongkeruanjian(编程亮子) 
    是地是地,你说得很对,我现在在写的东西就是UserInfo,DepartmentInfo...什么的定义了N多,经常定义类似这样的结构:
    DepartmentInfo
    {
    UserInfo manager;
    }结果察看部门列表的时候,记录少还行,记录多狂慢,最慢的一个查6000条记录的时候要4秒多,很不理想,后来考虑能不能在返回查询结果的时候就人为的分页,加快查询速度,费劲阿
    大家可以去http://expert.csdn.net/Expert/topic/3065/3065726.xml?temp=.3605463这几天问题不断...
      

  23.   

    我是这样安排的。
    如果需要复杂查询,我会使用存储过程,然后建立Users:DataSet,把它填充,里面实现两个方法,RowToUser(DataRow)和UserToRow(User),因为这样。把Row变成多层类的User对象
    而UserToRow是个private,只有当你输入 Add(User newUser)就会把多层次的类拆开成为
    字段,然后可以使用DataAdapter实现保存。
    但是,一般我不会直接使用DataAdapter,因为
    我处理的数据,都不会直接使用DataGrid或直接使用DataSet修改.所以所有的更新,我都不会使用 DataAdapter实现保存,因为DataAdapter很难实现快速开发,而且,面对4个Sql之间"@变量"
    对应多个列,很容易出错.虽然可以使用导航界面生成,但是不会很灵活,因为你显示的包括多个表间的各种数据。所以综合来说,查询使用存储过程,更新还是使用实体,DataSet也好,DataReader也好,对于我来说只是实现显示的方法。
      

  24.   

    Duwamish 的作法,就有一个毛病,烦,他的框架拉的也不算小,如果,一个人写,有点累,其实孙亚民的,WEBSHARP比较不错,你可以看一下,
      

  25.   

    最好的说明是代码,而不是什么文档,因为最接近“怎样实现”必定是代码。文档告诉你
    “要实现什么”。所以写出容易了解的代码,是一个中级程序员的基本要求。
    所以一直强调重构的几位大师,都要求,do one thing and do it well,
    有时间应该看看重构那本书,虽然里面的代码都是java,但是很好了解