ALI.ARPG.Operations
数据实体
[Serializable]
public class AccountEntity
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual string Password { get; set; }
}
[Serializable]
public class UserEntity
{
public virtual int ID { get; set; }
public virtual AccountEntity Account { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool Sex { get; set; }
}
ALI.ARPG.Data
Repository Pattern + Nhibernate + MySQL
Mapping
首先建立数据库和业务实体之间的映射关系,用到FluentNHibernate的Mapping功能
public class AccountMap : ClassMap<AccountEntity>
{
public AccountMap()
{
Table("account");
Id(x => x.ID).Column("id");
Map(x => x.Name).Column("name");
Map(x => x.Password).Column("password");
}
}
UserMap属性没写全,可以发现在Entity中,User是应用了Account实体,而数据映射仅Map了accountid。
public class UserMap : ClassMap<UserEntity>
{
public UserMap()
{
Table("user");
Id(x => x.ID);
References(x => x.Account).Column("accountid");
}
}
IRepository
定义Repository接口约束,常用的数据库CURD方法
public interface IReadOnlyRepository<T> where T : class
{
IEnumerable<T> All();
T FindBy(Expression<Func<T, bool>> expression);
IEnumerable<T> FilterBy(Expression<Func<T, bool>> expression);
}
public interface IRepository<T> : IReadOnlyRepository<T> where T : class
{
bool Add(T entity);
bool Add(IEnumerable<T> entities);
bool Update(T entity);
bool Delete(T entity);
bool Delete(IEnumerable<T> entities);
bool Delete(Expression<Func<T, bool>> expression);
}
public interface IIntKeyedRepository<T> : IRepository<T> where T : class
{
T FindBy(int id);
}
}
Repository
通过使用NHibernate, 对IRepository的实现
public class Repository<T> : IIntKeyedRepository<T> where T : class
{
private readonly ISession _session;
public Repository(ISession session)
{
this._session = session;
}
public bool Add(T entity)
{
this._session.Save(entity);
return true;
}
public bool Add(IEnumerable<T> entities)
{
foreach (T entity in entities)
{
this._session.Save(entity);
}
return true;
}
public bool Update(T entity)
{
this._session.Update(entity);
return true;
}
public bool Delete(T entity)
{
this._session.Delete(entity);
return true;
}
public bool Delete(IEnumerable<T> entities)
{
foreach (var entity in entities)
{
_session.Delete(entity);
}
return true;
}
public bool Delete(Expression<Func<T, bool>> expression)
{
IEnumerable<T> entities = FilterBy(expression);
return Delete(entities);
}
public T FindBy(int id)
{
return this._session.Get<T>(id);
}
public IEnumerable<T> All()
{
return this._session.QueryOver<T>().List();
}
public T FindBy(Expression<Func<T, bool>> expression)
{
return FilterBy(expression).Single();
}
public IEnumerable<T> FilterBy(Expression<Func<T, bool>> expression)
{
return this._session.QueryOver<T>().Where(expression).List();
}
}
XXXRepository
各业务实体的具体仓储类,如账号,用户,装备,技能等
public class UserRepository : Repository<UserEntity>
{
public UserRepository(ISession session) : base(session)
{
}
}
IUnitOfWork
工作单元类的接口约束
public interface IUnitOfWork : IDisposable
{
ISession Session { get; }
void Commit();
void Rollback();
}
UnitOfWork
工作单元,对一系列数据库操作,进行一次性事务提交,如要删除某个账号,首先要查询,如果不用UnitOfWork则会进行两次操作,而用UnitOfWork则只需要一次,而且用事物也可以避免脏数据的产生。
public class UnitOfWork : IUnitOfWork
{
private static readonly ISessionFactory _sessionFactory;
private ITransaction _transaction;
public ISession Session { get; private set; }
static UnitOfWork()
{
_sessionFactory = Fluently.Configure()
.Database(
MySQLConfiguration.Standard.ConnectionString(db =>
db.Server("localhost")
.Database("arpg")
.Username("root")
.Password("root")))
.Mappings(x => x.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.BuildSessionFactory();
}
public UnitOfWork()
{
Session = _sessionFactory.OpenSession();
Session.FlushMode = FlushMode.Auto;
_transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Commit()
{
if (!_transaction.IsActive)
{
throw new InvalidOperationException("No active transaction");
}
_transaction.Commit();
}
public void Dispose()
{
Session.Close();
}
public void Rollback()
{
if (_transaction.IsActive)
{
_transaction.Rollback();
}
}
}
单元测试
[TestClass]
public class UnitTestDataLayer
{
[TestMethod]
public void TestAddAccountMethod()
{
AccountEntity entity = new AccountEntity() {Name = "ali1", Password = "ali" };
UnitOfWork unitOfWork = new UnitOfWork();
AccountRepository account = new AccountRepository(unitOfWork.Session);
account.Add(entity);
unitOfWork.Commit();
}
[TestMethod]
public void TestGetAllAccountMethod()
{
UnitOfWork unitOfWork = new UnitOfWork();
AccountRepository account = new AccountRepository(unitOfWork.Session);
account.All();
unitOfWork.Commit();
}
[TestMethod]
public void TestGetAccountMethod()
{
UnitOfWork unitOfWork = new UnitOfWork();
AccountRepository account = new AccountRepository(unitOfWork.Session);
account.FilterBy(a => a.Name == "ali");
unitOfWork.Commit();
}
[TestMethod]
public void TestManyAccountMethod()
{
UnitOfWork unitOfWork = new UnitOfWork();
AccountRepository account = new AccountRepository(unitOfWork.Session);
var result = account.FilterBy(a => a.Name == "ali") as List<AccountEntity>;
unitOfWork.Commit();
Assert.AreEqual(result.Count, 1);
}
[TestMethod]
public void TestDeleteAccountMethod()
{
UnitOfWork unitOfWork = new UnitOfWork();
AccountRepository account = new AccountRepository(unitOfWork.Session);
account.Delete(a => a.Name == "ali");
unitOfWork.Commit();
}
}