接NHibernate 3.2实现Repository(ORuM)前文
使用NHibernate-->NHibernate.Linq-->Linq,结合NHibernate和LINQ的优势,使Repository的对象持久化和对象查询两方面兼优,实现了鱼和熊掌兼得。
使用LINQ重构Repository
修改Repository接口,使用LINQ减少方法,查询方法只有Query<TEntity>()。
using System;using System.Collections.Generic;using System.Linq;namespace MVCQuick.Framework.Repository{ public interface IRepository : IDisposable { void Save<TEntity>(TEntity entity) where TEntity : EntityBase; void Update<TEntity>(TEntity entity) where TEntity : EntityBase; void SaveOrUpdate<TEntity>(TEntity entity) where TEntity : EntityBase; void Delete<TEntity>(TEntity entity) where TEntity : EntityBase; TEntity Get<TEntity>(int id) where TEntity : EntityBase; IQueryable<TEntity> Query<TEntity>(); ITransaction BeginTransaction(); }}
NHibernate 实现
using System;using System.Collections.Generic;using System.Linq;using NH = NHibernate;using NHibernate.Linq;namespace MVCQuick.Framework.Repository.NHibernate{ public class NHibernateRepository : IRepository { private NH.ISession session; private bool useNHibernateManager = true; public NHibernateRepository() { } public NHibernateRepository(NH.ISession session) { this.session = session; this.useNHibernateManager = false; } public NH.ISession Session { get { if (!useNHibernateManager) { return session; } else { return NHibernateManager.GetCurrentSession(); } } } public void Save<TEntity>(TEntity entity) where TEntity : EntityBase { NH.ISession session = Session; session.Save(entity); session.Flush(); } public void Update<TEntity>(TEntity entity) where TEntity : EntityBase { NH.ISession session = Session; session.Update(entity); session.Flush(); } public void SaveOrUpdate<TEntity>(TEntity entity) where TEntity : EntityBase { NH.ISession session = Session; session.SaveOrUpdate(entity); session.Flush(); } public void Delete<TEntity>(TEntity entity) where TEntity : EntityBase { NH.ISession session = Session; session.Delete(entity); session.Flush(); } public TEntity Get<TEntity>(int id) where TEntity : EntityBase { NH.ISession session = Session; return session.Get<TEntity>(id); } public IQueryable<TEntity> Query<TEntity>() { NH.ISession session = Session; return session.Query<TEntity>(); } public ITransaction BeginTransaction() { NH.ISession session = Session; return new NHibernateTransaction(session); } public void Dispose() { if (this.session != null) { this.session.Flush(); CloseSession(); } } private void CloseSession() { session.Close(); session.Dispose(); session = null; } }}
AutoMapping部分代码见以前文章。
Repository成效
寥寥几行代码就实现了一个复杂的数据存储层,似乎不可思议,那就看看使用效果如何。
1、定义实体类
Entities.cs
using System;using System.Collections.Generic;namespace MVCQuick.Framework.Tests{ public class Album : EntityBase { public string Title { get; set; } public decimal Price { get; set; } public string AlbumArtUrl { get; set; } public Genre Genre { get; set; } public Artist Artist { get; set; } public void Add() { } } public class Genre : EntityBase { public string Name { get; set; } public string Description { get; set; } public IEnumerable<Album> Albums { get; set; } } public class Artist : EntityBase { public string Name { get; set; } public Address Address { get; set; } public IEnumerable<Album> Albums { get; set; } public IDictionary<String, String> Settings { get; set; } } public class User : EntityBase { public string Username { get; set; } public string Email { get; set; } public string Password { get; set; } public IEnumerable<Role> Roles { get; set; } public User() { Roles = new List<Role>(); } } public class Role : EntityBase { public string Name { get; set; } public string Description { get; set; } public IEnumerable<User> Users { get; set; } public Role() { Users = new List<User>(); } } public class Address : IValueObject { public string City { get; set; } public string Country { get; set; } public string State { get; set; } public string Street { get; set; } public string Zip { get; set; } }}
2、CRUD
IRepository repository = new NHibernateRepository(); User user = new User { Username = "admin", Email = "admin@163.com", Password = "admin123" }; repository.Save(user); user = repository.Get<User>(1); user.Password = "123456"; repository.Update(user); user = repository.Get<User>(1); repository.Delete(user);
3、Transaction
IRepository repository = new NHibernateRepository(); var Users = new List<User> { new User { Username = "刘备" , Email = "lb@123.com", Password = "123456" }, new User { Username = "曹操" , Email = "cc@123.com", Password = "123456" }, new User { Username = "孙权" , Email = "sq@123.com", Password = "123456" }, new User { Username = "曹植" , Email = "cz@123.com"}, new User { Username = "曹丕" , Email = "cp@123.com"}, new User { Username = "张飞" }, new User { Username = "关羽" }, new User { Username = "赵云" } }; ITransaction unitOfWork = repository.BeginTransaction();
foreach (var u in Users) { repository.Save(u); }
unitOfWork.Commit();
4、Query
IList<User> users; User user = null; users = repository.Query<User>() .ToList<User>(); Assert.AreEqual(users.Count, 8); //Where users = repository.Query<User>() .Where(x => x.Username == "刘备").ToList<User>(); Assert.AreEqual(users.Count, 1); Assert.AreEqual(users[0].Username, "刘备"); //OrderBy users = repository.Query<User>() .OrderByDescending(x => x.Id).ToList(); Assert.AreEqual(users[0].Username, "赵云"); //Skip, Take users = repository.Query<User>() .Skip(1 * 3).Take(3).ToList(); Assert.AreEqual(users.Count, 3); Assert.AreEqual(users[0].Username, "曹植"); //SingleOrDefault user = repository.Query<User>() .SingleOrDefault(x => x.Username == "刘备"); Assert.IsNotNull(user); Assert.AreEqual(user.Username, "刘备"); user = repository.Query<User>() .SingleOrDefault(x => x.Username == "诸葛亮"); Assert.IsNull(user); user = repository.Query<User>() .Where(x => x.Username == "刘备") .Where(x => x.Email == "lb@123.com") .SingleOrDefault(); Assert.IsNotNull(user); Assert.AreEqual(user.Username, "刘备"); //Count int count = repository.Query<User>() .Where(x => x.Email != null || x.Email.Length <= 0) .Count(); Assert.AreEqual(count, 5); }
Repository执行过程分析
1、实体类自动生成的HBM文件
<?xml version="1.0" encoding="utf-8"?><hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="MVCQuick.Framework.Tests" assembly="MVCQuick.Framework.Tests" xmlns="urn:nhibernate-mapping-2.2"> <class name="Album" lazy="false" table="MVCQuickTest_Albums"> <id name="Id" column="AlbumId" type="Int32"> <generator class="identity"/> </id> <version name="Version"/> <property name="Title"/> <property name="Price"/> <property name="AlbumArtUrl"/> <many-to-one name="Genre" column="GenreId"/> <many-to-one name="Artist" column="ArtistId"/> </class> <class name="Genre" lazy="false" table="MVCQuickTest_Genres"> <id name="Id" column="GenreId" type="Int32"> <generator class="identity"/> </id> <version name="Version"/> <property name="Name"/> <property name="Description"/> <bag name="Albums" inverse="true" cascade="all"> <key column="GenreId"/> <one-to-many class="Album"/> </bag> </class> <class name="Artist" lazy="false" table="MVCQuickTest_Artists"> <id name="Id" column="ArtistId" type="Int32"> <generator class="identity"/> </id> <version name="Version"/> <property name="Name"/> <component class="Address" name="Address"> <property name="City"/> <property name="Country"/> <property name="State"/> <property name="Street"/> <property name="Zip"/> </component> <bag name="Albums" inverse="true" cascade="all"> <key column="ArtistId"/> <one-to-many class="Album"/> </bag> <map name="Settings" table="MVCQuickTest_ArtistSettings" lazy="false"> <key column="ArtistId"/> <map-key type="String"/> <element type="String"/> </map> </class> <class name="User" lazy="false" table="MVCQuickTest_Users"> <id name="Id" column="UserId" type="Int32"> <generator class="identity"/> </id> <version name="Version"/> <property name="Username"/> <property name="Email"/> <property name="Password"/> <bag name="Roles" table="MVCQuickTest_RolesUsers" lazy="false"> <key column="UserId"/> <many-to-many class="Role" column="RoleId"/> </bag> </class> <class name="Role" lazy="false" table="MVCQuickTest_Roles"> <id name="Id" column="RoleId" type="Int32"> <generator class="identity"/> </id> <version name="Version"/> <property name="Name"/> <property name="Description"/> <bag name="Users" table="MVCQuickTest_RolesUsers" lazy="false"> <key column="RoleId"/> <many-to-many class="User" column="UserId"/> </bag> </class></hibernate-mapping>
2、自动生成的Sql建表语句
PRAGMA foreign_keys = OFF drop table if exists MVCQuickTest_Albums drop table if exists MVCQuickTest_Genres drop table if exists MVCQuickTest_Artists drop table if exists MVCQuickTest_ArtistSettings drop table if exists MVCQuickTest_Users drop table if exists MVCQuickTest_RolesUsers drop table if exists MVCQuickTest_Roles PRAGMA foreign_keys = ON create table MVCQuickTest_Albums ( AlbumId integer primary key autoincrement, Version INT not null, Title TEXT, Price NUMERIC, AlbumArtUrl TEXT, GenreId INT, ArtistId INT, constraint FKC10717EEF1D1C255 foreign key (GenreId) references MVCQuickTest_Genres, constraint FKC10717EEAECFE1CE foreign key (ArtistId) references MVCQuickTest_Artists ) create table MVCQuickTest_Genres ( GenreId integer primary key autoincrement, Version INT not null, Name TEXT, Description TEXT ) create table MVCQuickTest_Artists ( ArtistId integer primary key autoincrement, Version INT not null, Name TEXT, City TEXT, Country TEXT, State TEXT, Street TEXT, Zip TEXT ) create table MVCQuickTest_ArtistSettings ( ArtistId INT not null, id TEXT, idx TEXT not null, primary key (ArtistId, idx), constraint FK62D35A09AECFE1CE foreign key (ArtistId) references MVCQuickTest_Artists ) create table MVCQuickTest_Users ( UserId integer primary key autoincrement, Version INT not null, Username TEXT, Email TEXT, Password TEXT ) create table MVCQuickTest_RolesUsers ( UserId INT not null, RoleId INT not null, constraint FK92B56EE2860D4243 foreign key (RoleId) references MVCQuickTest_Roles, constraint FK92B56EE27DFC8936 foreign key (UserId) references MVCQuickTest_Users ) create table MVCQuickTest_Roles ( RoleId integer primary key autoincrement, Version INT not null, Name TEXT, Description TEXT )
3、生成的Sql查询语句
select user0_.UserId as UserId16_, user0_.Version as Version16_, user0_.Username as Username16_, user0_.Email as Email16_, user0_.Password as Password16_ from MVCQuickTest_Users user0_select user0_.UserId as UserId16_, user0_.Version as Version16_, user0_.Username as Username16_, user0_.Email as Email16_, user0_.Password as Password16_ from MVCQuickTest_Users user0_ where user0_.Username=@p0;@p0 = '刘备' [Type: String (0)]select user0_.UserId as UserId16_, user0_.Version as Version16_, user0_.Username as Username16_, user0_.Email as Email16_, user0_.Password as Password16_ from MVCQuickTest_Users user0_ order by user0_.UserId descselect user0_.UserId as UserId16_, user0_.Version as Version16_, user0_.Username as Username16_, user0_.Email as Email16_, user0_.Password as Password16_ from MVCQuickTest_Users user0_ limit @p0 offset @p1;@p0 = 3 [Type: Int32 (0)], @p1 = 3 [Type: Int32 (0)]select user0_.UserId as UserId16_, user0_.Version as Version16_, user0_.Username as Username16_, user0_.Email as Email16_, user0_.Password as Password16_ from MVCQuickTest_Users user0_ where user0_.Username=@p0;@p0 = '刘备' [Type: String (0)]select user0_.UserId as UserId16_, user0_.Version as Version16_, user0_.Username as Username16_, user0_.Email as Email16_, user0_.Password as Password16_ from MVCQuickTest_Users user0_ where user0_.Username=@p0;@p0 = '诸葛亮' [Type: String (0)]select user0_.UserId as UserId16_, user0_.Version as Version16_, user0_.Username as Username16_, user0_.Email as Email16_, user0_.Password as Password16_ from MVCQuickTest_Users user0_ where user0_.Username=@p0 and user0_.Email=@p1;@p0 = '刘备' [Type: String (0)], @p1 = 'lb@123.com' [Type: String (0)]select cast(count(*) as INT) as col_0_0_ from MVCQuickTest_Users user0_ where user0_.Email is not null or length(user0_.Email)<=@p0;@p0 = 0 [Type: Int32 (0)]
一切尽在掌握!
Repository(ORuM)的实现过程感兴趣,可以看看前面的博文,在此不再详述。
源代码下载:http://mvcquick.codeplex.com/
来源:https://www.cnblogs.com/guyoung/archive/2011/10/23/2221787.html