NHibernate初学者指南(14):配置的三种方式
XML配置
配置NHibernate最初是通过XML。我们有两种方式可以定义配置,一种是Windows应用程序的应用程序配置文件,另一种是基于web的应用程序的Web.config文件。我们也可以在单独的XML文件中定义配置。
下面我们通过一个例子,实现一个简单的应用程序,使用NHibernate持久化数据并从关系数据库中读取数据。我们使用的数据库是SQLite。
1. 打开Visual Studio,创建一个控制台应用程序:XmlConfigurationSample。
2. 在Solution Explorer中,右击XmlConfigurationSample项目,选择属性,在Application选项卡中,将Target framework设置为.NET Framework3.5。
3. 在Build选项卡中,确保Platform Target设置为了Any CPU。
4. 添加对NHibernate.dll, NHibernate.ByteCode.Castle.dll和System.Data.SQLite.dll程序集的引用。
5. 在解决方案中添加一个解决方案文件夹:Schema。
6. 在Schema解决方案文件夹中添加两个文件:nhibernate-configuration.xsd和nhibernate-mapping.xsd。
7. 在项目中添加一个类文件:Account.cs,添加如下代码:
public class Account { public int Id { get; set; } public string Name { get; set; } public decimal Balance { get; set; } public string CurrencyCode { get; set; } public bool IsActive { get; set; } }
8. 在项目中添加一个XML文件:Account.hbm.xls用于定义Account实体的映射,代码如下所示:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="XmlConfigurationSample" namespace="XmlConfigurationSample" > <class name="Account" lazy="false"> <id name="Id"> <generator class="hilo"/> </id> <property name="Name"/> <property name="Balance"/> <property name="CurrencyCode"/> <property name="IsActive"/> </class> </hibernate-mapping>
9. 设置Account.hbm.xml的BuilAction属性为:Embedded Resource。
10. 打开项目中的app.config文件(如果没有添加一个),定义一个section:
<?xml version="1.0"?> <configuration> <configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" /> </configSections> </configuration>
11. 在configSections后面,添加如下代码:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="connection.provider"> NHibernate.Connection.DriverConnectionProvider </property> <property name="connection.driver_class"> NHibernate.Driver.SQLite20Driver </property> <property name="dialect"> NHibernate.Dialect.SQLiteDialect </property> <property name="proxyfactory.factory_class"> NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle </property> <property name="connection.connection_string_name"> Sample </property> <property name="show_sql"> true </property> </session-factory> </hibernate-configuration>
12. 在上面代码的后面再定义一个数据库连接字符串,代码如下:
<connectionStrings> <add name="Sample" connectionString="data source=xmlconfig.dbf;version=3;new=true;"/> </connectionStrings>
13. 在Program类中添加如下代码,前面都提到过了,这里把所有代码一下子贴出来了。
class Program { static void Main(string[] args) { var configuration = new Configuration(); configuration.AddAssembly(typeof(Account).Assembly); BuildSchema(configuration); var factory = configuration.BuildSessionFactory(); using (var session = factory.OpenSession()) { var account = new Account { Name = "USB-10234-R1", Balance = 1545.55m, CurrencyCode = "CHF", IsActive = true }; session.Save(account); session.Flush(); session.Clear(); var fromDb = session.Get<Account>(account.Id); System.Console.Write("\r\n\nHit enter to exit:"); System.Console.ReadLine(); } } private static void BuildSchema(Configuration configuration) { new SchemaExport(configuration).Execute(true, true, false); } }
14. 运行程序,结果如下图所示:
代码中配置
如果不在XML中配置,也可以在代码中定义所有的配置。
下面还是通过一个例子,实现一个简单的应用程序,所有的配置都在代码中定义。
1. 打开SSMS,创建一个数据库:CodeConfigurationSample。
2. 打开Visual Studio创建一个控制台应用程序:CodeConfigurationSample。
3. 添加对Nhibernate.dll和NHibernate.ByteCode.Castle.dll程序集的引用。
4. 在解决方案中添加一个解决方案文件夹:Schema。
5. 在Schema解决方案文件夹中添加两个文件:nhibernate-configuration.xsd和nhibernate-mapping.xsd。
6. 在项目中添加一个类文件Product.cs,添加如下代码定义Product实体:
public class Product { public int Id { get; set; } public string Name { get; set; } public decimal UnitPrice { get; set; } public int ReorderLevel { get; set; } public int UnitsOnStock { get; set; } public bool Discontinued { get; set; } }
7. 添加一个XML文件:Product.hbm.xml,同时将它的BuildAction设置为Embedded Resource。
8. 在Product.hbm.xml中添加如下代码定义Product实体的映射:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="CodeConfigurationSample" namespace="CodeConfigurationSample" > <class name="Product" lazy="false"> <id name="Id"> <generator class="hilo"/> </id> <property name="Name"/> <property name="UnitPrice"/> <property name="ReorderLevel"/> <property name="UnitsOnStock"/> <property name="Discontinued"/> </class> </hibernate-mapping>
9. 在Program类中添加一个静态方法GetConfiguration,代码如下:
private static Configuration GetConfiguration() { }
10. 首先,我们在GetConfiguration方法中,创建一个Configuration类型的实例,代码如下:
var cfg = new Configuration();
11. 下面通过Add方法,往Properties集合中添加键值对,定义NHibernate使用的ConnectionProvider,ConnectionDriver,Dialect,ProxyFactoryFactoryClass等等,代码如下:
cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionProvider, typeof(DriverConnectionProvider).FullName); cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionDriver, typeof(SqlClientDriver).FullName); cfg.Properties.Add(NHibernate.Cfg.Environment.Dialect, typeof(MsSql2008Dialect).FullName); cfg.Properties.Add(NHibernate.Cfg.Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName); cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionString, @"server=.;database=CodeConfigurationSample;integrated security=SSPI;"); cfg.Properties.Add(NHibernate.Cfg.Environment.ShowSql, "true");
12. 现在需要声明想使用的映射,我们既可以单独的添加实体类型,也可以添加包含所有XML配置文件的程序集,代码分别如下:
//cfg.AddClass(typeof(Product)); cfg.AddAssembly(typeof(Product).Assembly);
13. 最后返回cfg。
return cfg;
14. 在Program里定义另一个静态方法BuildSchema,代码如下:
private static void BuildSchema(Configuration configuration) { new SchemaExport(configuration).Execute(true, true, false); }
15. 下面在Main方法中添加如下代码:
static void Main(string[] args) { var configuration = GetConfiguration(); BuildSchema(configuration); var factory = configuration.BuildSessionFactory(); using (var session = factory.OpenSession()) { var product = new Product { Name = "Apple", UnitPrice = 1.55m, ReorderLevel = 10, UnitsOnStock = 5 }; session.Save(product); session.Flush(); session.Clear(); var fromDb = session.Get<Product>(product.Id); System.Console.Write("\r\n\nHit enter to exit:"); System.Console.ReadLine(); }
16. 运行程序,结果如下图所示:
17. 一般情况下,我们并不想将连接字符串定义在代码中,而是放在配置文件中。我们可以在项目中添加一个App.config文件,添加如下代码:
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="Sample" connectionString="server=.;database=CodeConfigurationSample;integrated security=SSPI;"/> </connectionStrings> </configuration>
18. 在GetConfiguration方法中,修改连接字符串如下:
cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionStringName, "Sample");
19. 再次运行程序即可。
Fluent配置
使用Loquacious配置NHibernate
NHibernate为配置包含了一个新的fluent API。这个API定义在Loquacious命名空间中,它包含了配置的所有方面。
跟之前一样,我们不讨论太多的理论,而是直接深入例子。在这个例子中,使用前面提到的一些概念,如值对象的使用和NHibernate Profiler工具。
1. 打开Visual Studio,创建一个控制台应用程序:LoquaciousConfigurationSample。
2. 在这个例子中我们还是使用SQLite作为数据库,因此需要相应的调整一下项目设置。在Solution Explorer,右击选择属性,在Application选项卡中选择.NET Framework 3.5作为Target framework,在Build选项卡中确保Platform target设置为Any CPU。
4. 在解决方案中添加一个解决方案文件夹:Schema,在其中添加两个文件:nhibernate-configuration.xsd和nhibernate-mapping.xsd。
5. 在项目中添加对以下程序集的引用:
- NHibernate.dll
- NHibernate.ByteCode.Castle.dll
- HibernatingRhinos.Profiler.Appender.dll
- System.Data.SQLite.dll
6. 如果项目中没有app.config文件,则添加一个并添加如下代码:
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="Sample" connectionString="data source=loquaciousConfig.dbf;version=3;new=true;"/> </connectionStrings> </configuration>
7. 在项目中添加一个类文件:Person.cs,添加如下代码定义Person实体:
public class Person { public Guid Id { get; set; } public Name Name { get; set; } public string SSN { get; set; } public DateTime Birthdate { get; set; } }
8. 添加另一个类文件:Name.cs,添加如下代码定义Name值对象:
public class Name { public string FirstName { get; set; } public string LastName { get; set; } public string MiddleName { get; set; } public bool Equals(Name other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(other.FirstName, FirstName) && Equals(other.LastName, LastName) && Equals(other.MiddleName, MiddleName); } public override bool Equals(object obj) { if (obj.GetType() != typeof(Name)) return false; return Equals((Name)obj); } public override int GetHashCode() { unchecked { int result = (FirstName != null ? FirstName.GetHashCode() : 0); result = (result * 397) ^ (LastName != null ? LastName.GetHashCode() : 0); result = (result * 397) ^ (MiddleName != null ? MiddleName.GetHashCode() : 0); return result; } } }
9. 在项目中添加一个XML文件:Person.hbm.xml,并将它的Build Action属性设置为Embedded Resource。
10. 在Person.hbm.xml中添加如下代码定义Person实体的映射:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="LoquaciousConfigurationSample" namespace="LoquaciousConfigurationSample" > <class name="Person" lazy="false"> <id name="Id"> <generator class="guid.comb"/> </id> <component name="Name"> <property name="FirstName"/> <property name="LastName"/> <property name="MiddleName"/> </component> <property name="SSN"/> <property name="Birthdate"/> </class> </hibernate-mapping>
11. 我们Main方法中添加以下代码使用NHibernate Profiler数据库通过NHibernate与应用程序的通信:
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
12. 最后使用位于NHibernate.Cfg.Loquacious命名空间中的fluent API配置NHibernate。首先在Program类中添加一个静态方法:GetConfiguratioin,它包含以下配置的代码:
private static Configuration GetConfiguration() { var cfg = new Configuration(); cfg.Proxy(p => { p.ProxyFactoryFactory<ProxyFactoryFactory>(); }); cfg.DataBaseIntegration(db => { db.ConnectionProvider<DriverConnectionProvider>(); db.Driver<SQLite20Driver>(); db.Dialect<SQLiteDialect>(); db.ConnectionStringName = "Sample"; db.LogSqlInConsole = true; }); cfg.AddAssembly(typeof(Person).Assembly); return cfg; }
13. 然后在Program类中再添加一个静态方法:BuildSchema,用来重新创建数据库架构
private static void BuildSchema(Configuration configuration) { new SchemaExport(configuration).Execute(true, true, false); }
14. 最后在Main方法中添加如下代码,跟前面两个例子是一样的:
var configuration = GetConfiguration(); BuildSchema(configuration); var factory = configuration.BuildSessionFactory(); using (var session = factory.OpenSession()) { var person = new Person { Name = new Name { LastName = "Doe", FirstName = "John", MiddleName = "A." }, Birthdate = new DateTime(1977, 1, 6), SSN = "111-22-3333" }; session.Save(person); session.Flush(); session.Clear(); var fromDb = session.Get<Person>(person.Id); Console.Write("\r\n\nHit enter to exit:"); Console.ReadLine();
15. 启动NHibernate Profiler。
16. 运行程序,监视NHibernate Profiler的输出,如下图所示:
17. 可以看到使用了两个session,第一个用来重新创建数据库架构,第二个用来保存和加载person对象。让我们仔细的看一下创建表的脚本,如下图:
18. 让我们看一下INSERT语句,如下图所示:
19. 最后看一下SELECT语句,如下图所示:
总结
本篇通过三个例子分别演示了NHibernate配置的三种方式,即XML配置,代码中配置,和使用NHibernate的fluent API配置。文中都给出了完整的代码,还有所涉及到的知识跟前面紧密相连。