NHibernate Step by Step( 二 ) 单表操作
接着第一期,我们继续。
为了方便学习测试,从今天开始我将使用 MS Test 来进行测试,这样就避免了在一个 Console 工程里不停地添加、注释代码了。
    
      提示:为了在
    
    
      VS2005IDE
    
    
      中获得
    
    
      NHibernate
    
    
      配置文件的代码提示,请将你的
    
    
      $NHibernate/src/NHibernate
    
    
      下的
    
    
      nhibernate-configuration-2.0.xsd
    
    
      、
    
    
      nhibernate-mapping-2.0.xsd
    
    
      拷贝到
    
    
      /Program Files/Microsoft Visual Studio 8/Xml/Schemas
    
    
      下,这样当你编辑配置文件或者映射文件时,你将得到完整的代码提示。
      
      VS2003请拷贝到/Program Files/Microsoft Visual Studio .NET 2003/Common7/Packages/schemas/xml下。
      
    
    
    
  
NHibernat 内部使用 log4net 来进行日志操作,今天我们将在配置文件中添加 log4net 的配置,这样我们在测试的时候将可以清楚地看到 NHibernate 是如何进行工作的。
    
      应用配置文件修改如下:
      
    
  
 <?
    
    
      xmlversion="1.0"encoding="utf-8"
    
    
      ?>
    
      <?
    
    
      xmlversion="1.0"encoding="utf-8"
    
    
      ?>
    
    
       <
    
    
      configuration
    
    
      >
    
    
      <
    
    
      configuration
    
    
      >
    
    
       <
    
    
      configSections
    
    
      >
    
    
      <
    
    
      configSections
    
    
      >
    
    
       <
    
    
      section
    
    
      name
    
    
      ="nhibernate"
    
    
      type
    
    
      ="System.Configuration.NameValueSectionHandler,System,Version=1.0.5000.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
    
    
    
    
      />
    
    
      <
    
    
      section
    
    
      name
    
    
      ="nhibernate"
    
    
      type
    
    
      ="System.Configuration.NameValueSectionHandler,System,Version=1.0.5000.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
    
    
    
    
      />
    
    
       <
    
    
      section
    
    
      name
    
    
      ="log4net"
    
    
      type
    
    
      ="log4net.Config.Log4NetConfigurationSectionHandler,log4net"
    
    
    
    
      />
    
    
      <
    
    
      section
    
    
      name
    
    
      ="log4net"
    
    
      type
    
    
      ="log4net.Config.Log4NetConfigurationSectionHandler,log4net"
    
    
    
    
      />
    
    
       </
    
    
      configSections
    
    
      >
    
    
      </
    
    
      configSections
    
    
      >
    
    
       
       <
    
    
      nhibernate
    
    
      >
    
    
      <
    
    
      nhibernate
    
    
      >
    
    
       <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.provider"
    
    
      value
    
    
      ="NHibernate.Connection.DriverConnectionProvider"
    
    
    
    
      />
    
    
      <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.provider"
    
    
      value
    
    
      ="NHibernate.Connection.DriverConnectionProvider"
    
    
    
    
      />
    
    
       <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.driver_class"
    
    
      value
    
    
      ="NHibernate.Driver.SqlClientDriver"
    
    
    
    
      />
    
    
      <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.driver_class"
    
    
      value
    
    
      ="NHibernate.Driver.SqlClientDriver"
    
    
    
    
      />
    
    
       <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.connection_string"
    
    
      value
    
    
      ="Server=localhost;InitialCatalog=NHibernate;IntegratedSecurity=SSPI"
    
    
    
    
      />
    
    
      <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.connection_string"
    
    
      value
    
    
      ="Server=localhost;InitialCatalog=NHibernate;IntegratedSecurity=SSPI"
    
    
    
    
      />
    
    
       <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.isolation"
    
    
      value
    
    
      ="ReadCommitted"
    
    
      />
    
    
      <
    
    
      add
    
    
      key
    
    
      ="hibernate.connection.isolation"
    
    
      value
    
    
      ="ReadCommitted"
    
    
      />
    
    
       <
    
    
      add
    
    
      key
    
    
      ="hibernate.dialect"
    
    
      value
    
    
      ="NHibernate.Dialect.MsSql2000Dialect"
    
    
    
    
      />
    
    
      <
    
    
      add
    
    
      key
    
    
      ="hibernate.dialect"
    
    
      value
    
    
      ="NHibernate.Dialect.MsSql2000Dialect"
    
    
    
    
      />
    
    
       <
    
    
      add
    
    
      key
    
    
      ="show_sql"
    
    
      value
    
    
      ="true"
    
    
    
    
      />
    
    
      <
    
    
      add
    
    
      key
    
    
      ="show_sql"
    
    
      value
    
    
      ="true"
    
    
    
    
      />
    
    
       </
    
    
      nhibernate
    
    
      >
    
    
      </
    
    
      nhibernate
    
    
      >
    
    
       
       <
    
    
      log4net
    
    
      >
    
    
      <
    
    
      log4net
    
    
      >
    
    
       <
    
    
      appender
    
    
      name
    
    
      ="ConsoleAppender"
    
    
      type
    
    
      ="log4net.Appender.ConsoleAppender"
    
    
    
    
      >
    
    
      <
    
    
      appender
    
    
      name
    
    
      ="ConsoleAppender"
    
    
      type
    
    
      ="log4net.Appender.ConsoleAppender"
    
    
    
    
      >
    
    
       <
    
    
      layout
    
    
      type
    
    
      ="log4net.Layout.PatternLayout"
    
    
      >
    
    
      <
    
    
      layout
    
    
      type
    
    
      ="log4net.Layout.PatternLayout"
    
    
      >
    
    
       <
    
    
      conversionPattern
    
    
      value
    
    
      ="%date[%thread]%-5level%logger[%ndc]-%message%newline"
    
    
    
    
      />
    
    
      <
    
    
      conversionPattern
    
    
      value
    
    
      ="%date[%thread]%-5level%logger[%ndc]-%message%newline"
    
    
    
    
      />
    
    
       </
    
    
      layout
    
    
      >
    
    
      </
    
    
      layout
    
    
      >
    
    
       </
    
    
      appender
    
    
      >
    
    
      </
    
    
      appender
    
    
      >
    
    
       <
    
    
      root
    
    
      >
    
    
      <
    
    
      root
    
    
      >
    
    
       <
    
    
      level
    
    
      value
    
    
      ="ALL"
    
    
    
    
      />
    
    
      <
    
    
      level
    
    
      value
    
    
      ="ALL"
    
    
    
    
      />
    
    
       <
    
    
      appender-ref
    
    
      ref
    
    
      ="ConsoleAppender"
    
    
    
    
      />
    
    
      <
    
    
      appender-ref
    
    
      ref
    
    
      ="ConsoleAppender"
    
    
    
    
      />
    
    
       </
    
    
      root
    
    
      >
    
    
      </
    
    
      root
    
    
      >
    
    
       
       </
    
    
      log4net
    
    
      >
    
    
      </
    
    
      log4net
    
    
      >
    
    
       
       </
    
    
      configuration
    
    
      >
    
    
      </
    
    
      configuration
    
    
      >
    
    
       
    
  
    
  
请注意添加:
 <
    
    
      add
    
    
      key
    
    
      ="show_sql"
    
    
      value
    
    
      ="true"
    
    
    
    
      />
    
      <
    
    
      add
    
    
      key
    
    
      ="show_sql"
    
    
      value
    
    
      ="true"
    
    
    
    
      />
    
  
关于 log4net 的使用,我们这里不做详细的讲解,有兴趣的请参考如下地址:
http://logging.apache.org/log4net/
接着,我们在上次的工程组中添加一个名为 Test1 的测试项目,将其中的不需要的手动测试去掉。请注意:除了 NHibernate/Model 引用外,还需要添加如下 3 个引用:
    
      log4net,System.Data,System.Xml.
      
    
  
    
      
      修改代码如下:
    
  
 using
    
    
      System;
    
      using
    
    
      System;
       using
    
    
      System.Text;
    
    
      using
    
    
      System.Text;
       using
    
    
      System.Collections;
    
    
      using
    
    
      System.Collections;
       using
    
    
      Microsoft.VisualStudio.TestTools.UnitTesting;
    
    
      using
    
    
      Microsoft.VisualStudio.TestTools.UnitTesting;
       using
    
    
      NHibernate;
    
    
      using
    
    
      NHibernate;
       using
    
    
      NHibernate.Cfg;
    
    
      using
    
    
      NHibernate.Cfg;
       using
    
    
      log4net;
    
    
      using
    
    
      log4net;
       using
    
    
      log4net.Config;
    
    
      using
    
    
      log4net.Config;
       using
    
    
      Test.Model;
    
    
      using
    
    
      Test.Model;
       
       namespace
    
    
      Test1
    
    
      namespace
    
    
      Test1
       {
      
    
    
    
      
        {
         ///
        
        
        
        
          <summary>
        
      
      
      
        
          ///
        
        
        
        
          <summary>
        
        
           ///
        
        
          SummarydescriptionforUnitTest1
        
        
          ///
        
        
          SummarydescriptionforUnitTest1
           ///
        
        
        
        
          </summary>
        
        
          ///
        
        
        
        
          </summary>
        
        
        
      
       [TestClass]
      
        [TestClass]
         public
      
      
      
      
        class
      
      
        UnitTest1
      
      
        public
      
      
      
      
        class
      
      
        UnitTest1
         {
        
      
      
      
        
          {
           static
        
        
          ISessionFactoryfactory;
        
        
          static
        
        
          ISessionFactoryfactory;
           static
        
        
          ILoglogger;
        
        
          static
        
        
          ILoglogger;
           ISessionsession;
          ISessionsession;
           
           public
        
        
          UnitTest1()
        
        
          public
        
        
          UnitTest1()
           {
          
        
        
        
          
            {
             }
            }
          
        
        
           
           Additionaltestattributes
          
        
        
          Additionaltestattributes
        
        
        
           }
          }
        
      
      
         }
        }
      
    
    
       
    
  
    
      我们在测试的开始对
    
    
      Configuration/SessionFactory/Log
    
    
      进行初始化。在每一个
    
    
      Test
    
    
      的开始获取一个新的
    
    
      session
    
    
      ,每一个
    
    
      Test
    
    
      结束后即关闭
    
    
      session
    
    
      。
      
    
  
    
      
      添加如下一个
    
    
      Get
    
    
      测试:
    
    
    
  
 [TestMethod]
    
      [TestMethod]
       public
    
    
    
    
      void
    
    
      TestRead()
    
    
      public
    
    
    
    
      void
    
    
      TestRead()
       {
      
    
    
    
      
        {
         Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
        Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
         Assert.IsTrue(person.Name
      
      
        ==
      
      
      
      
        "
      
      
        JackieChan
      
      
        "
      
      
        );
        Assert.IsTrue(person.Name
      
      
        ==
      
      
      
      
        "
      
      
        JackieChan
      
      
        "
      
      
        );
         }
        }
      
    
    
       
    
  
    
    我们在前面曾经插入一条名为“Jackie Chan”的记录,现在在Test Manager中选中TestRead,运行,ok,Passed!
    
    我们使用了session.Get来获取记录,方法如下:
  
object Get( Type clazz , object id );
    
      很简单,一目了然。
      
    
  
    
      
      我们切换到
    
    
      Test Results
    
    
      窗口,双击测试成功的
    
    
      TestRead
    
    
      方法,这时将会有一个详细的测试结果显示出来,
    
    
      NHibernate
    
    
      将使用我们指定的
    
    
      log4net
    
    
      来输出详细信息,我们仔细观察:
      
    
  
    
      
      2006-04-15 13:52:13,000 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - opened session
    
  
2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - loading [Person#1]
2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - attempting to resolve [Person#1]
2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - object not resolved in any cache [Test.Model.Person#1]
    
      2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Persister.EntityPersister [(null)] - Materializing entity: Test.Model.Person#1
      
    
  
    
      
        
        2006-04-15 13:52:13,078 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Opened new IDbCommand, open IDbCommands :1
      
    
  
2006-04-15 13:52:13,078 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Building an IDbCommand object for the SqlString: SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=:id
2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.Type.Int32Type [(null)] - binding '1' to parameter: 0
2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] INFO NHibernate.Loader.Loader [(null)] - SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=@p0
2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=@p0
    
      
        2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - @p0 = '1'
        
      
    
  
    
      
      2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.Connection.DriverConnectionProvider [(null)] - Obtaining IDbConnection from Driver
    
  
2006-04-15 13:52:13,859 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Opened Reader, open Readers :1
2006-04-15 13:52:13,859 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - processing result set
2006-04-15 13:52:13,875 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - result row: 1
2006-04-15 13:52:13,875 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - Initializing object from DataReader: 1
2006-04-15 13:52:13,875 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - Hydrating entity: Test.Model.Person#1
2006-04-15 13:52:13,906 [AdpaterExeMgrThread1] DEBUG NHibernate.Type.StringType [(null)] - returning 'Jackie Chan' as column: name0_
2006-04-15 13:52:13,906 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - done processing result set (1 rows)
2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Driver.NHybridDataReader [(null)] - running NHybridDataReader.Dispose()
2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Closed Reader, open Readers :0
2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Closed IDbCommand, open IDbCommands :0
2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - total objects hydrated: 1
2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - resolving associations for: [Test.Model.Person#1]
2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - done materializing entity [Test.Model.Person#1]
2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - initializing non-lazy collections
2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - closing session
2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - disconnecting session
2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Connection.ConnectionProvider [(null)] - Closing connection
2006-04-15 13:52:13,968 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - transaction completion
    
      在其中,我们可以发现:
      
    
  
    
      
      2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=@p0
    
  
    
      2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - @p0 = '1'
      
    
  
    
      
      对了,就是这里,
    
    
      NHibernate
    
    
      替我们构造了一条
    
    
      sql
    
    
      语句,并添加一个参数,然后将我们在代码中赋的
    
    
      id
    
    
      值
    
    
      1
    
    
      来填充,这样,一条完整的可以执行的
    
    
      sql
    
    
      语句产生了。
    
  
请注意:在产生 sql 语句的前面, NHibernate 构造了一个 IDBCommand ,然后在 sql 语句产生完全后,获取连接,通过一个 DataReader 来填充 Persion 对象给我们使用,这就是 NHibernate 替我们做的事,是不是很简单啊?(真的很简单吗??看看源代码吧!!)
请仔细研究输出的日志。
如法炮制,我们添加另外 3 个 Test ,完成单个表的全部 CRUD 操作,如下完整代码:
 [TestMethod]
    
      [TestMethod]
       
       public
    
    
    
    
      void
    
    
      TestCreate()
    
    
      public
    
    
    
    
      void
    
    
      TestCreate()
       
       {
      
    
    
    
      
        {
         
         Personperson
      
      
        =
      
      
      
      
        new
      
      
        Person();
        Personperson
      
      
        =
      
      
      
      
        new
      
      
        Person();
         
         person.Name
      
      
        =
      
      
      
      
        "
      
      
        JackieChan
      
      
        "
      
      
        ;
        person.Name
      
      
        =
      
      
      
      
        "
      
      
        JackieChan
      
      
        "
      
      
        ;
         
         
         
         ITransactiontrans
      
      
        =
      
      
        session.BeginTransaction();
        ITransactiontrans
      
      
        =
      
      
        session.BeginTransaction();
         
         try
      
      
        try
      
      
         
         {
        
      
      
      
        
          {
           
           session.Save(person);
          session.Save(person);
           
           trans.Commit();
          trans.Commit();
           
           Assert.IsTrue(person.Id
        
        
          >
        
        
        
        
          0
        
        
          );
          Assert.IsTrue(person.Id
        
        
          >
        
        
        
        
          0
        
        
          );
           
           }
          }
        
      
      
         
         catch
      
      
        (Exceptionex)
      
      
        catch
      
      
        (Exceptionex)
         
         {
        
      
      
      
        
          {
           
           trans.Rollback();
          trans.Rollback();
           
           Assert.Fail(ex.Message);
          Assert.Fail(ex.Message);
           
           }
          }
        
      
      
         
         }
        }
      
    
    
       
       
       
       [TestMethod]
      [TestMethod]
       
       public
    
    
    
    
      void
    
    
      TestUpdate()
    
    
      public
    
    
    
    
      void
    
    
      TestUpdate()
       
       {
      
    
    
    
      
        {
         
         Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
        Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
         
         person.Name
      
      
        =
      
      
      
      
        "
      
      
        JetLi
      
      
        "
      
      
        ;
        person.Name
      
      
        =
      
      
      
      
        "
      
      
        JetLi
      
      
        "
      
      
        ;
         
         
         
         ITransactiontrans
      
      
        =
      
      
        session.BeginTransaction();
        ITransactiontrans
      
      
        =
      
      
        session.BeginTransaction();
         
         try
      
      
        try
      
      
         
         {
        
      
      
      
        
          {
           
           session.Save(person);
          session.Save(person);
           
           trans.Commit();
          trans.Commit();
           
           Assert.IsTrue(person.Name
        
        
          ==
        
        
        
        
          "
        
        
          JetLi
        
        
          "
        
        
          );
          Assert.IsTrue(person.Name
        
        
          ==
        
        
        
        
          "
        
        
          JetLi
        
        
          "
        
        
          );
           
           }
          }
        
      
      
         
         catch
      
      
        (Exceptionex)
      
      
        catch
      
      
        (Exceptionex)
         
         {
        
      
      
      
        
          {
           
           trans.Rollback();
          trans.Rollback();
           
           Assert.Fail(ex.Message);
          Assert.Fail(ex.Message);
           
           }
          }
        
      
      
         
         }
        }
      
    
    
       
       
       
       [TestMethod]
      [TestMethod]
       
       public
    
    
    
    
      void
    
    
      TestRead()
    
    
      public
    
    
    
    
      void
    
    
      TestRead()
       
       {
      
    
    
    
      
        {
         
         Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
        Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
         
         Assert.IsTrue(person.Name
      
      
        ==
      
      
      
      
        "
      
      
        JackieChan
      
      
        "
      
      
        );
        Assert.IsTrue(person.Name
      
      
        ==
      
      
      
      
        "
      
      
        JackieChan
      
      
        "
      
      
        );
         
         }
        }
      
    
    
       
       
       
       [TestMethod]
      [TestMethod]
       
       public
    
    
    
    
      void
    
    
      TestDelete()
    
    
      public
    
    
    
    
      void
    
    
      TestDelete()
       
       {
      
    
    
    
      
        {
         
         Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
        Personperson
      
      
        =
      
      
        (Person)session.Get(
      
      
        typeof
      
      
        (Person),
      
      
        1
      
      
        );
         
         
         
         ITransactiontrans
      
      
        =
      
      
        session.BeginTransaction();
        ITransactiontrans
      
      
        =
      
      
        session.BeginTransaction();
         
         try
      
      
        try
      
      
         
         {
        
      
      
      
        
          {
           
           session.Delete(person);
          session.Delete(person);
           
           trans.Commit();
          trans.Commit();
           
           }
          }
        
      
      
         
         catch
      
      
        (Exceptionex)
      
      
        catch
      
      
        (Exceptionex)
         
         {
        
      
      
      
        
          {
           
           trans.Rollback();
          trans.Rollback();
           
           Assert.Fail(ex.Message);
          Assert.Fail(ex.Message);
           
           }
          }
        
      
      
         
         }
        }
      
    
    
       
       
    
  
Delete 的方法如下:
直接传入需要 delete 的对象即可。
    
      好了,基本的操作都完成了,是不是很Easy?
      
    
    
    
  
    
      好了,这一篇就讲这么多,我们下次再接着练习。
      
    
  
Step by Step ,顾名思义,是一步一步来的意思,整个教程我将贯彻这一理念。
任何建议或者批评,请 e : abluedog@163.com


 
     
     
					 
					