• 我的NHibernate曲折之行【转】


    首先我对那些,自己认为被我前天的博文设计模式点滴系列(一)鸭子传说中污染到你们视觉的朋友,说声对不起。特别是那些说我的文章没水平或者是抄袭《Head First Design Patterns》第一章的朋友。我承认我的文章没有什么特色,但是我相信在学习中能跨出第一步还是至关重要的。并且我相信,在园子里面有很多没有看过《Head First》的朋友,在看完我的文章之后会去了解这本书,从而吸取书中的精华。这难道不是一个效果吗?所以我相信,即使再瑕疵的东西也能挑出亮点来!
         今天我仍旧厚着脸皮,讲述我的NHibernate曲折之行。男人的胸怀是委屈撑大的,多一点委屈,少一些脾气你会更快乐。
         之前,看过很多NHibernate的东西。特别是 YJingLeeNHibernate之旅系列比较经典。看得多了,但是还没有真正的从头到尾的做过一边。今天从头到尾做了一遍,发现问题还真多。我就将我做的过程和在这中间碰到的问题跟大家分享一下。也可以让一些初学的朋友少走一些弯路,当然我碰到的很多问题在网上都能找到答案,我也就将一些需要注意点,和出错的点收集一下,然后放到一起,节省大家时间去疯狂Google。大致过程参照YJingLee的NHibernate之旅(2):第一个NHibernate程序。不过YJingLee用的是NUnit测试框架,我这里直接用了一个Windows Form项目来做测试。
         我用的开发环境:Visual Studio 2008SP1+SQL Server 2008 + NHibernate-2.1.0.GA最新版
         首先新建一个空的解决方案,命名为NHibernateSimpale,然后新建三个项目分别为DAL类库项目,Model项目,NHibernateTest窗体项目。
         然后删除掉自动生成的Class1.cs.



         我这里为了演示这个流程,就只创建了一个最简单的数据库,在文章的末尾我会提供将源代码和数据库执行脚本下载。
         我新建了一个NHibernate数据库,然后新建三张表,经典的Student,Course,StudentCourse。其实真正用到了就一张表Student。
         我这里使用的O/R Mapping的工具是mygeneration。我将其生成的映射文件和实体类文件的两个文件夹Entities和Mappings拷贝至Model文件夹下面,然后将其包含进项目中。这里注意了,第一个问题出现了,我当时在生成映射文件的时候在另外一个路径下,所以生成的默认的命名空间需要改成我现在的Model.Entities的命名空间。  
        在NHibernateTest里面添加三个配置文件,App.config,NHibernateMSSQL.config,NHibernateOracle.config其中第一个是用来存放数据库的链接字符串的,当然后别的用途。第二个,第三个是用来做NHibernate的配置文件的。这里我是为了实现多数据库的NHibernate的支持。可以让程序有一个比较好的数据库的扩展性。下次如果要从MSSQL换成Oracle或者MYSql只要修改或者增加一个配置文件就OK。
        在DAL项目中添加两个类,GetStudent.cs,SessionManager.cs,第一个是用来获取学生信息的。第二个是用来管理NHibernate中的Session,可以说相当于一个帮助类。
       经过以上步骤得到如下的结果。当然是没有任何代码的。
        
     
    接下来先检查Student.hbm.xml中的

    <?xml version="1.0" encoding="utf-8"?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
      <class name="Model.Entities.Student,Model" table="Student" lazy="true">
        <id name="StudentId" column="StudentId" type="int">
          <generator class="native" />
        </id>
        <property type="string" length="40" name="StudentName" column="[StudentName]" />
        <property type="string" length="20" name="StudentPassword" column="[StudentPassword]" />
        <property type="string" length="40" name="EmailAddress" column="[EmailAddress]" />
        <property type="DateTime" name="DateCreated" column="[DateCreated]" />
      </class>
    </hibernate-mapping>
    
    

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
      <class name="Model.Entities.Student,Model" table="Student" lazy="true">



    这里要注意是2.2,不是2.0。
    其次是在下面的Model.Entities.Student,Model这里前者是实体,后者是程序集。这个当然只有初学者会有点疑问。

    接下来是增加应用程序配置文件信息,首先是在App.config里面加上

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <connectionStrings>
        <!--<add name="Connection String" connectionString="Data Source=YeanJay;User Id=YeanJay;Password=YeanJay;Persist Security Info=true" providerName="System.Data.OracleClient"/>-->
        <add name="Connection String" connectionString="Data Source=YeanJay;Database=NHibernate;uid=YeanJay;pwd=YeanJay" providerName="System.Data.SqlClient"/>
    
      </connectionStrings>
    </configuration>
    

    这里只是增加了数据库链接字符串,注意:这里的Connection String在NHibernate的配置文件中要用到,所以要保持一致。这里如果要将数据库从MSSql迁移到Oracle,那么我们只要将上面的注释去掉,然后将下面这句MSSQL的注释掉就可以了。
    然后来看NHibernate的两个配置文件:NHibernateMSSQL.config和NHibernateOracle.config
    >NHibernateMSSQL.config

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
      <session-factory name="northwind">
        <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="connection.connection_string_name">Connection String</property>
        <property name="connection.isolation">ReadCommitted</property>
        <!-- Mapping Files -->
        <mapping assembly="Model"/>
      </session-factory>
    </hibernate-configuration>
    


    >NHibernateOracle.config

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
      <session-factory name="northwind">
        <property name="dialect">NHibernate.Dialect.Oracle10Dialect</property>
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
        <property name="connection.driver_class">NHibernate.Driver.OracleClientDriver</property>
        <property name="connection.connection_string_name">Connection String</property>
        <property name="connection.isolation">ReadCommitted</property>
    
        <!-- Mapping Files -->
        <mapping assembly="Model"/>
      </session-factory>
    </hibernate-configuration>
    

    这里有一个<mapping assembly="Model">就是之前提到的那个映射实体类的那个程序集。
    在开始编写代码之前,我们需要将一些需要的引用添加到每个工程里面:
    DAL:引用Model项目和NHibernate.dll
    Model:引用Iesi.Collections.dll和NHibernate.dll
    在WinForm项目中:根据YJingLee的例子是引用DAL,Model这两个项目,和NHibernate.dll,暂时我们也这么引用。
    现在开始编写代码:
    SessionManager.cs类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using NHibernate;
    using NHibernate.Cfg;
    using Model;
    
    namespace DAL
    {
        public class SessionManager
        {
            ISessionFactory _sessionfactory;
            public SessionManager()
            {
                _sessionfactory = GetSessionFactory();
            }
    
            public ISessionFactory GetSessionFactory()
            {
                Configuration ctg = new Configuration().Configure("./NHibernateMSSQL.config");
                //ctg.AddAssembly("Model");
                //return (new Configuration()).Configure().BuildSessionFactory();
                return ctg.BuildSessionFactory();
            }
    
            public ISession GetSession()
            {
                return _sessionfactory.OpenSession();
            }
        }
    }

         这里的Configuration ctg = new Configuration().Configure("./NHibernateMSSQL.config");的方式在NHibernate的灵活配置 有讲到。
         当然这里的"./NHibernateMSSQL.config"在实际生产中一般不要写到这里来,一般是从配置文件中读取过来。这里为了方便,我就直接写在这里了。
         这里我也没有去关心这个线程安全不安全的问题了。见谅!

    SessionManager.cs类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using NHibernate;
    using Model.Entities;
    //using NHibernate.Cfg;
    
    namespace DAL
    {
        public class GetStudent
        {
            private ISession _session;
    
            public ISession Session
            {
                set { _session = value; }
            }
    
            public GetStudent(ISession session)
            {
                _session = session;
            }
    
            public Student GetStudentById(int studentId)
            {
                return _session.Get<Student>(studentId);
            }
        }
    }

        
    Form.cs 代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    using DAL;
    using NHibernate;
    using Model.Entities;
    namespace NHibernateTest
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private ISession _session;
            private SessionManager _helper = new SessionManager();
            private GetStudent _getStudent;
            private void Form1_Load(object sender, EventArgs e)
            {
                _session = _helper.GetSession();
                _getStudent = new GetStudent(_session);
    
                Student student = _getStudent.GetStudentById(1);
                this.textBox1.Text = student.StudentName;
                this.textBox2.Text = student.StudentPassword;
            }
        }
    }

    OK,开始执行。
    叮!第一个错误跳出来:
    “NHibernate.Cfg.Configuration”的类型初始值设定项引发异常。
    查看详细信息:
    未能加载文件或程序集“log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821”或它的某一个依赖项。
    系统找不到指定的文件。

    第一次想到在DAL中加入log4net.dll(这个dll在下载过来的最新版的NHibernate的bin文件夹下有的)。没想到问题依然存在,那好,就先撤销在DAL中的log4net,然后直接到Winform下添加log4net结果错误消失了。但是第二个错误 咚!又出来了!


    The following types may not be used as proxies:

    Model.Entities.Course:method get_IsDeleted should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Course: method set_IsDeleted should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Course: method get_IsChanged should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Course: method set_IsChanged should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Course: method Clone should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.StudentCourse: method get_IsDeleted should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.StudentCourse: method set_IsDeleted should be 'public/protected virtual' or 'protected internal virtual'


    Model.Entities.StudentCourse: method get_IsChanged should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.StudentCourse: method set_IsChanged should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.StudentCourse: method Clone should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Student: method get_IsDeleted should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Student: method set_IsDeleted should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Student: method get_IsChanged should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Student: method set_IsChanged should be 'public/protected virtual' or 'protected internal virtual'

    Model.Entities.Student: method Clone should be 'public/protected virtual' or 'protected internal virtual'


        这个就是在老赵今天发的我对NHibernate的感受(2):何必到处都virtual的提到的到处都是Virtual了,在MyGeneration生成的映射文件中,有些方法并不是Virtural的,所以会出现编译通过,但是执行出错的情况。
       解决方案,当然是在每个方法和属性上面加上Virtual了。

    处理完这个错误,当然还是没有那么顺利就过关啦,第三个错误依旧报来!

    这也就是需要注意的另外一点:在2.1版本中的NHibernate中需要在NHibernate配置文件中加入
    <property name='proxyfactory.factory_class'>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
    这样一节,这个来源于YJingLee博客里的一个答复。

    加入以后,继续编译,执行。叮叮!!又来一错误:

    “NHibernate.ByteCode.Castle.ProxyFactory”的类型初始值设定项引发异常。
    查看详细信息:
    未能加载文件或程序集“Castle.DynamicProxy2, Version=2.1.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc”或它的某一个依赖项。
    系统找不到指定的文件。
    当然应该也是2.1的版本的缘故咯。然后继续到源码文件夹下的bin目录下找到这个DLL,添加。具体信息可以参考这里
    继续编译执行。继续出错:

    未能加载文件或程序集“Castle.Core, Version=1.0.3.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc”或它的某一个依赖项。系统找不到指定的文件。

    神呐,继续找问题,继续添加引用。
    继续编译。现在发现在Winform下的引用已经很多了。都是NHibernate2.1执行的依赖项。
    全部添加完,相变的引用如下:

    这些引用都可以在NHibernate源码的bin目录下可以找到。
    接下来编译。测试通过!!!
    执行的界面如下:


    数据库执行脚本下载项目源代码下载

  • 相关阅读:
    layer 弹窗使用说明
    从零开始写代码 Python 8分钟实现Floyd最短路径算法
    vue项目中使用SVGICON
    jeecgbootvue3笔记(六)主子组件数据加载
    jeecgbootvue3AntDesign笔记(十四)——异步调用后端
    【转载】net core中调用webservice
    QNX 命令行总结
    C++中%作为引导符的使用总结
    流程自动化RPA,Power Automate Desktop系列 流程挖掘(Process Mining),正成为海外大厂的兵家必争之地
    乘风破浪,遇见最美Windows 11之新微软商店(Microsoft Store)生态 万兴科技旗下18款应用入驻微软商店,Wondershare Filmora斩获微软应用商店编辑精选奖
  • 原文地址:https://www.cnblogs.com/tangge/p/2560626.html
Copyright © 2020-2023  润新知