贴子地址:
http://community.csdn.net/Expert/topic/5263/5263804.xml?temp=.772793其中LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^) 回答道:==========================
很多人有这个困惑,分层后一旦要修改一个数据库字段需要把所有的层都修改一遍。往往这是由于你的指责不明确引起的。假如您的数据访问层仅仅做的是对某种数据库的数据访问操作,不涉及任何的业务,那么即使修改了表结构,数据访问层不需要修改任何代码。加入您的表现层仅仅是根据业务模型呈现数据,即使我们把字段名从Username修改成了name,由于业务层返回的还是原来的业务实体,表现层也不需要做任何改动。反之,您直接把从数据库中SELECT的记录通过DataSet返回给表现层,那么修改了数据表字段后肯定也要修改表现层。
===========================我纳闷:我的DataLayer层代码        public IList<AttackSpeedInfo> GetAttackSpeedList(string PlayerID, string OtherID, string Flag)
        {
            IList<AttackSpeedInfo> AllAttackSpeed = new List<AttackSpeedInfo>();
            
            string procName = "sp_Attack";
            DBManager.Open();
            SqlDatabase db = DBManager.DB;
            DbCommand Procdbcomm = db.GetStoredProcCommand(procName);
            db.AddInParameter(Procdbcomm, "@PlayerID", DbType.String);
            db.AddInParameter(Procdbcomm,"@OtherID",DbType.String);
            db.AddInParameter(Procdbcomm,"@Flag",DbType.String);            db.SetParameterValue(Procdbcomm, "@PlayerID", PlayerID);
            db.SetParameterValue(Procdbcomm,"@OtherID",OtherID);
            db.SetParameterValue(Procdbcomm,"@Flag",Flag);            using (IDataReader reader = db.ExecuteReader(Procdbcomm))
            {
                while (reader.Read()) //玩家
                {
                    AttackSpeedInfo attackspeed = new AttackSpeedInfo();//此处为Model对象
                    attackspeed.UserName = reader["UserName"].ToString();
                    attackspeed.T = float.Parse(reader["T"].ToString());
                    attackspeed.ID = reader["ID"].ToString();
                    AllAttackSpeed.Add(attackspeed);
                }            }
            return AllAttackSpeed;
        }问:如果我在数据库中修改UserName ,难道attackspeed.UserName = reader["UserName"].ToString();这个不能修改?我没有办法来理解他说的.请高人指点我

解决方案 »

  1.   

    AttackSpeedInfo attackspeed = new AttackSpeedInfo();//此处为Model对象
                        attackspeed.UserName = reader["UserName"].ToString();
    试问:
    按他的意思,在数据库中修改UserName为Name,他说他的数据层不用改..至少要改成:attackspeed.Name = reader["Name"].ToString();才对吧?
    当在数据库中把UserName改成Name后,Model实体中也应该把对应的UserName改为Name吧? 
      

  2.   

    attackspeed.UserName = reader["UserName"].ToString();
    这个字段修改了名字当然要改过来,你曲解了他的意思了,实行分层后修改了表结构可能需要改的只是数据层,而业务逻辑层涉及的和数据库表并没有直接关系,所以不用修改,而表示层是根据业务逻辑来呈现数据,所以也不用修改
      

  3.   

    应该是表结构改动了,或者数据库改动了,比如说以前用Access,现在升级到SQL Server,如果你的三层分得好,那么需要改动的也只是你的数据层而已...你的逻辑层和表示层并不需要改动,逻辑层是怎么做,数据层是做,它实际上是数据库和程序的一个中间层
      

  4.   

    按他的意思,在数据库中修改UserName为Name,他说他的数据层不用改..不是这个意思而是说数据库由Sql server转到Oracle上不变。
    如果你想UserName改成Name后实体类能自动映射,可以去看Castle
      

  5.   

    实行分层后修改了表结构可能需要改的只是数据层,而业务逻辑层涉及的和数据库表并没有直接关系,所以不用修改,而表示层是根据业务逻辑来呈现数据,所以也不用修改
    =========================================
    说的正确。
    另外最好不要用reader["字段名"]这样提取值。
      

  6.   

    首先谢谢二位高人的回答.你们把问题说明清了..另外:
    我的逻辑层(BLL)中的代码为: private static readonly IAtlas dal = WebGame.DALFactory.DataAccess.CreateAtlas();
            public AtlasInfo AtlasProperty(int AtlasID)
            {
                return dal.AtlasProperty(AtlasID); //几乎所有的方法都是这样子
            }合理吗?我完全是按petshop4.0中的做法来处理的.
      

  7.   

    TO:lovehongyun(一个人的电影) 另外最好不要用reader["字段名"]这样提取值。
    ==============
    不用这种,用哪种呢?难道还有其它更加方便的.请讲
      

  8.   

    说明你的层还没分好using (IDataReader reader = db.ExecuteReader(Procdbcomm))
    {
    while (reader.Read()) //玩家
    {
    AttackSpeedInfo attackspeed = new AttackSpeedInfo();//此处为Model对象
    attackspeed.UserName = reader["UserName"].ToString();
    attackspeed.T = float.Parse(reader["T"].ToString());
    attackspeed.ID = reader["ID"].ToString();
    AllAttackSpeed.Add(attackspeed);
    }}==>
    using (IDataReader reader = db.ExecuteReader(Procdbcomm))
    {
    while (reader.Read()) //玩家
    {
    AttackSpeedInfo attackspeed = new AttackSpeedInfo(reader);//此处为Model对象
    //attackspeed.UserName = reader["UserName"].ToString();
    //attackspeed.T = float.Parse(reader["T"].ToString());
    //attackspeed.ID = reader["ID"].ToString();
    //AllAttackSpeed.Add(attackspeed);
    }}
    然后实现AttackSpeedInfo 由reader构造
    现在如果修改了数据库中的字段,你只需要修改AttackSpeedInfo类,也仅仅只需要修改它
      

  9.   

    blackant2(乔峰)
    ==============
    天天.你回答的太有道理了..!~~~~~~~~~~~~我一定要尝试去做...一针见血
      

  10.   

    TO:mapserver(杨东 http://mapserver.cnblogs.com)
    ===========
    Castlep 这是啥来着?简单讲讲..
      

  11.   

    赞成楼上的偶用的是一个ORM,只需要重新生成一编数据库接口类就可以了业务层引用对象时,对象的属性当然要改改了,但是表现层就不用改了
      

  12.   

    小问一下:LZ的reader用完之后不关闭是不是不太好啊?
      

  13.   

    你这样的数据层的意义局限于今后需要移植其它数据库只需要修改数据层。由于没有使用通用数据访问,不能做到修改了表结构这些添加、删除和修改操作也不需要修改。因此,这样的数据访问层不能说是真正意义上的数据访问层。真正的数据访问层是不涉及任何数据库结构(甚至是兼容多种数据库)并提供数据的一般化操作(添加、删除、修改、查询等)的一个框架(比如ORM框架、SQLMAP框架)。而且应该把IList<AttackSpeedInfo> 的组装提升到业务层来做
      

  14.   

    lovcal(枫兮):我关闭了,只是有部分代码没我贴出来.
      

  15.   

    TO:LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^) 其中你说道:
    ================
    而且应该把IList<AttackSpeedInfo> 的组装提升到业务层来做
    ================我这种做法完全是按Microsoft中的petshop4.0来做的.贴一段petshop4.0代码给你看
    public IList<ItemInfo> GetItemsByProduct(string productId) {            IList<ItemInfo> itemsByProduct = new List<ItemInfo>();            SqlParameter parm = new SqlParameter(PARM_PRODUCT_ID, SqlDbType.VarChar, 10);
                parm.Value = productId;            //Execute the query against the database
    using(SqlDataReader rdr = SqlHelper.ExecuteReader(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_ITEMS_BY_PRODUCT, parm)) {
                    // Scroll through the results
                    while (rdr.Read()) {
                        ItemInfo item = new ItemInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetInt32(2), rdr.GetDecimal(3), rdr.GetString(4), rdr.GetString(5), rdr.GetString(6), rdr.GetString(7));
                        //Add each item to the arraylist
                        itemsByProduct.Add(item);
                    }
                }
                return itemsByProduct;
            }
      

  16.   

    难道我不能相信Microsoft中的petshop4.0做法?
      

  17.   

    这个是仁者见仁智者见智的问题,我说的也仅仅是个人的想法,不一定对的。 分层与构架常常是论坛上讨论的热点,新的构架技术往往会得到很多人的吹捧和追随,笔者认为,应该在一个客观的角度来看待这些技术,否则很容易走入误区。常见的误区有:
    &#61548; 模仿别人的构架
    很多人喜欢模仿微软的一些作品(PETSHOP等)作为自己项目的构架,确实这些作品给我们展示了很多新思想、优秀的设计模式和构架,但是我们不能盲目模仿,而应该根据自己的项目寻找最合适的构架。在一个对性能要求特别高而对扩展要求不高的项目上大量使用解耦框架,显然偏离了项目的初衷。而构架往往决定了整个项目的性能和可靠性,因此,在构架的选择上需要慎重,不要盲目模仿和追新。
    &#61548; 不断使用新的构架使得项目看上去很“先进”
    我们知道,每一种构架都不是凭空产生的,而有很多人却喜欢凭空去使用它们。构架都是在实际的开发过程中遇到问题、解决问题发展而来的,每一种构架都有它们的优势和主要针对的问题。要知道,灵活和性能往往是一对矛盾,越是灵活的构架可能越复杂越庞大,如果我们不需要这种灵活性就完全没有必要使用复杂的构架来提升项目的“技术含量”。
      

  18.   

    PetShop只是一个范例,没叫你照着做。
      

  19.   

    TO:LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^)首先我要感谢你的回复其中你说道:
    ==================
    真正的数据访问层是不涉及任何数据库结构(甚至是兼容多种数据库)并提供数据的一般化操作(添加、删除、修改、查询等)的一个框架(比如ORM框架、SQLMAP框架)。
    ==================
    能否大概讲一下.最好有一个简短的例子.谢谢你
      

  20.   

    while (reader.Read()) //玩家
    {
    AttackSpeedInfo attackspeed = new AttackSpeedInfo(reader);//此处为Model对象
    //attackspeed.UserName = reader["UserName"].ToString();
    //attackspeed.T = float.Parse(reader["T"].ToString());
    //attackspeed.ID = reader["ID"].ToString();
    AllAttackSpeed.Add(attackspeed);
    }===>
    看看我们这样写的时候加了什么,省略了什么
    多了一个AttackSpeedInfo构造方法
    省略了属性的指定
    //attackspeed.UserName = reader["UserName"].ToString();
    //attackspeed.T = float.Parse(reader["T"].ToString());
    //attackspeed.ID = reader["ID"].ToString();所以常见的
    AttackSpeedInfo(IDataReader)
    应该是如下形式public AttackSpeedInfo(IDataReader reader){
    UserName = reader["UserName"].ToString();
    T = float.Parse(reader["T"].ToString());
    ID = reader["ID"].ToString();
    //...........
    }同理可以实现由datarow/datarowview实现的构造
    那么以后可以直接构造AttackSpeedInfo类并使用
    不用关心它实现的细节,我们要的仅是AttackSpeedInfosqldatareader sda=...
    while (sda.read()){
      AttackSpeedInfo asi=new AttackSpeedInfo(sda)
    }更进一步的方法是实现由AttackSpeedInfo自己实现sql并构造本身public AttackSpeedInfo{
      public static AttackSpeedInfo getbyUserName(string name){
        //实现从数据库中取得idatareader reader
        //然后由datareader构造
         return new AttackSpeedInfo(reader)
      } 
    }
    这样外部的调用与sql也无关了AttackSpeedInfo  asi=AttackSpeedInfo .getbyUserName('我的名字')
    就要以得到AttackSpeedInfo对象
      

  21.   

    谢谢blackant2(乔峰) 再次回答