使用NHibernate 3.2实现Repository(ORuM)(十二)Repository、LINQ

接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 desc
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_ 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/   

posted @ 2011-10-23 15:19  GuYoung  阅读(1611)  评论(1编辑  收藏  举报