本篇介绍Entity Framework 实体框架的文章已经到了第十篇了,对实体框架的各个分层以及基类的封装管理,已经臻于完善,为了方便对基类接口的正确性校验,以及方便对以后完善或扩展接口进行回归测试,那么建立单元测试就有很大的必要,本篇主要介绍如何利用VS创建内置的单元测试项目进行实体框架的基类接口测试。

在采用单元测试这个事情上,很多人可能想到了NUnit单元测试工具和NMock工具进行处理,其实微软VS里面也已经为我们提供了类似的单元测试工具了,可以不需要使用这个第三方的单元测试工具,经试用VS的单元测试工具还是整合性很好,使用非常方便的。

1、实体框架架构及基础类库接口

在上次的随笔《Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合》里面,我根据实体框架中混合模式的框架结构,所涉及的架构图形如下所示。

我们从上图可以看到,整个框架从下往上分为了几个明显的层次,一个数据访问层DAL层,一个是业务逻辑层BLL层,一个是Facade门面层,各个层的功能不同,这几个层中以DAL层最为复杂一些,涉及到底层多种数据库的抽象实现,由于Entity Framework 实体框架本身就是对多种数据库的实现抽象,因此本文重点针对这个DAL层进行单元测试。

其中的实体框架的公用类库(WHC.Framework.EF),里面涉及到的IBaseDAL就是数据访问层的基类接口,具体数据访问的抽象实现就在BaseDAL的基类上。

在IBaseDAL接口里面,定义了很多我们数据访问类需要使用的增删改查、分页、统计、辅助方法等接口,以及各个方法的异步方法接口,如下所示。

namespace WHC.Framework.EF
{
/// <summary>
/// 数据访问层基类接口
/// </summary>
/// <typeparam name="T">实体对象类型</typeparam>
public interface IBaseDAL<T> where T : class
{
#region 对象添加、修改、删除 /// <summary>
/// 插入指定对象到数据库中
/// </summary>
/// <param name="t">指定的对象</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
bool Insert(T t); /// <summary>
/// 插入指定对象到数据库中(异步)
/// </summary>
/// <param name="t">指定的对象</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
Task<bool> InsertAsync(T t); /// <summary>
/// 插入指定对象集合到数据库中
/// </summary>
/// <param name="list">指定的对象集合</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
bool InsertRange(IEnumerable<T> list); /// <summary>
/// 插入指定对象集合到数据库中(异步)
/// </summary>
/// <param name="list">指定的对象集合</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
Task<bool> InsertRangeAsync(IEnumerable<T> list); /// <summary>
/// 更新对象属性到数据库中
/// </summary>
/// <param name="t">指定的对象</param>
/// <param name="key">主键的值</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
bool Update(T t, object key); /// <summary>
/// 更新对象属性到数据库中(异步)
/// </summary>
/// <param name="t">指定的对象</param>
/// <param name="key">主键的值</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c></returns>
Task<bool> UpdateAsync(T t, object key); /// <summary>
/// 根据指定对象的ID,从数据库中删除指定对象
/// </summary>
/// <param name="id">对象的ID</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
bool Delete(object id); /// <summary>
/// 根据指定对象的ID,从数据库中删除指定对象(异步)
/// </summary>
/// <param name="id">对象的ID</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
Task<bool> DeleteAsync(object id); /// <summary>
/// 从数据库中删除指定对象
/// </summary>
/// <param name="t">指定对象</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
bool Delete(T t); /// <summary>
/// 从数据库中删除指定对象(异步)
/// </summary>
/// <param name="t">指定对象</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
Task<bool> DeleteAsync(T t); /// <summary>
/// 根据指定条件,从数据库中删除指定对象
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
bool DeleteByExpression(Expression<Func<T, bool>> match); /// <summary>
/// 根据指定条件,从数据库中删除指定对象(异步)
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
Task<bool> DeleteByExpressionAsync(Expression<Func<T, bool>> match); /// <summary>
/// 根据指定条件,从数据库中删除指定对象
/// </summary>
/// <param name="condition">删除记录的条件语句</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
bool DeleteByCondition(string condition); /// <summary>
/// 根据指定条件,从数据库中删除指定对象(异步)
/// </summary>
/// <param name="condition">删除记录的条件语句</param>
/// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns>
Task<bool> DeleteByConditionAsync(string condition); #endregion

或者一些其他的分页等复杂的实现接口。

        #region 返回集合的接口

        /// <summary>
/// 返回可查询的记录源
/// </summary>
/// <returns></returns>
IQueryable<T> GetQueryable(); /// <summary>
/// 根据条件表达式返回可查询的记录源
/// </summary>
/// <param name="match">查询条件</param>
/// <param name="sortPropertyName">排序表达式</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns></returns>
IQueryable<T> GetQueryable(Expression<Func<T, bool>> match, string sortPropertyName, bool isDescending = true); /// <summary>
/// 根据条件表达式返回可查询的记录源
/// </summary>
/// <param name="match">查询条件</param>
/// <param name="orderByProperty">排序表达式</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns></returns>
IQueryable<T> GetQueryable<TKey>(Expression<Func<T, bool>> match, Expression<Func<T, TKey>> orderByProperty, bool isDescending = true); /// <summary>
/// 返回数据库所有的对象集合
/// </summary>
/// <returns></returns>
IList<T> GetAll(); /// <summary>
/// 返回数据库所有的对象集合(异步)
/// </summary>
/// <returns></returns>
Task<IList<T>> GetAllAsync(); /// <summary>
/// 返回数据库所有的对象集合
/// </summary>
/// <param name="orderByProperty">排序表达式</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns></returns>
IList<T> GetAll<TKey>(Expression<Func<T, TKey>> orderByProperty, bool isDescending = true); /// <summary>
/// 返回数据库所有的对象集合(异步)
/// </summary>
/// <param name="orderByProperty">排序表达式</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns></returns>
Task<IList<T>> GetAllAsync<TKey>(Expression<Func<T, TKey>> orderByProperty, bool isDescending = true); /// <summary>
/// 返回数据库所有的对象集合(用于分页数据显示)
/// </summary>
/// <param name="match">条件表达式</param>
/// <param name="info">分页实体</param>
/// <returns>指定对象的集合</returns>
IList<T> GetAllWithPager(PagerInfo info); /// <summary>
/// 返回数据库所有的对象集合(用于分页数据显示,异步)
/// </summary>
/// <param name="info">分页实体</param>
/// <returns>指定对象的集合</returns>
Task<IList<T>> GetAllWithPagerAsync(PagerInfo info); /// <summary>
/// 根据条件查询数据库,并返回对象集合
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns></returns>
IList<T> Find(Expression<Func<T, bool>> match); /// <summary>
/// 根据条件查询数据库,并返回对象集合(异步)
/// </summary>
/// <param name="match">条件表达式</param>
/// <returns></returns>
Task<IList<T>> FindAsync(Expression<Func<T, bool>> match); /// <summary>
/// 根据条件查询数据库,并返回对象集合
/// </summary>
/// <param name="match">条件表达式</param>
/// <param name="orderByProperty">排序表达式</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns></returns>
IList<T> Find<TKey>(Expression<Func<T, bool>> match, Expression<Func<T, TKey>> orderByProperty, bool isDescending = true); /// <summary>
/// 根据条件查询数据库,并返回对象集合(异步)
/// </summary>
/// <param name="match">条件表达式</param>
/// <param name="orderByProperty">排序表达式</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns></returns>
Task<IList<T>> FindAsync<TKey>(Expression<Func<T, bool>> match, Expression<Func<T, TKey>> orderByProperty, bool isDescending = true); /// <summary>
/// 根据条件查询数据库,并返回对象集合(用于分页数据显示)
/// </summary>
/// <param name="match">条件表达式</param>
/// <param name="info">分页实体</param>
/// <returns>指定对象的集合</returns>
IList<T> FindWithPager(Expression<Func<T, bool>> match, PagerInfo info); /// <summary>
/// 根据条件查询数据库,并返回对象集合(用于分页数据显示,异步)
/// </summary>
/// <param name="match">条件表达式</param>
/// <param name="info">分页实体</param>
/// <returns>指定对象的集合</returns>
Task<IList<T>> FindWithPagerAsync(Expression<Func<T, bool>> match, PagerInfo info); /// <summary>
/// 根据条件查询数据库,并返回对象集合(用于分页数据显示)
/// </summary>
/// <param name="match">条件表达式</param>
/// <param name="info">分页实体</param>
/// <param name="orderByProperty">排序表达式</param>
/// <param name="isDescending">如果为true则为降序,否则为升序</param>
/// <returns>指定对象的集合</returns>
IList<T> FindWithPager<TKey>(Expression<Func<T, bool>> match, PagerInfo info, Expression<Func<T, TKey>> orderByProperty, bool isDescending = true); #endregion

以及更多的方法接口,我们为了校验没有接口都能够正常工作,就需要对它们进行单元测试。

2、在VS里面创建单元测试项目及编写单元测试代码

在VS里面创建内置的单元测试项目如下所示,在添加新项目里面选择测试->单元测试项目即可,如下图所示。

为了方便对基类测试,我们还是需要创建一个简单的代表性数据库用来检查基础的接口操作。

由于前面的系列,已经介绍过了,我们在构建数据访问层的时候,使用的是基于IOC的方式构建一个对象的接口对象,如这样代码IFactory.Instance<IUserDAL>()所示。

而单元测试,基本原理就是我们调用接口,并获取对应的输出结果,和我们预期的值进行对比,如果吻合就是正常通过的测试用例。

为了进行基础类库的单元测试,我们需要根据实体框架的结构搭建一个具体表的对象项目工程,这个采用代码生成工具Database2Sharp进行生成就可以了,生成的处理操作如下所示。

这样根据表快速生成的整个实体框架,就是我们所需要的实体框架项目,具体效果如下所示。

例如我们创建一个查找记录的单元测试方法代码如下所示。

namespace TestFrameworkEF
{
[TestClass]
public class TestBaseDAL
{
private string userId = Guid.NewGuid().ToString(); [TestInitialize]
public void Init()
{
User user = new User() { ID = userId, Account = "Nunit", Password = "Nunit" }; bool result = IFactory.Instance<IUserDAL>().Insert(user);
Assert.AreEqual(result, true);
} [TestCleanup]
public void Cleanup()
{
bool result = IFactory.Instance<IUserDAL>().Delete(userId);
Assert.AreEqual(result, true);
} [TestMethod]
public void FindByID()
{
User user = IFactory.Instance<IUserDAL>().FindByID(userId); Assert.IsNotNull(user);
Assert.AreEqual(user.ID, userId);
}

其中上面红色代码部分就是单元测试的各种标识,包括单元测试类标识,以及初始化、退出清除、测试用例的标识。

上面案例,我们是在单元测试前,在数据库写入一条记录,然后在进行各种单元测试用例的运行及校验,最后退出的时候,清除我们写入的记录。

而记录的更新和删除接口,我们具体的单元测试代码如下所示。

        [TestMethod]
public void Update()
{
string newAccount = "Test";
User user = IFactory.Instance<IUserDAL>().FindByID(userId);
user.Account = newAccount;
bool result = IFactory.Instance<IUserDAL>().Update(user, user.ID);
Assert.AreEqual(result, true); user = IFactory.Instance<IUserDAL>().FindByID(userId);
Assert.IsNotNull(user);
Assert.AreEqual(user.Account, newAccount);
} [TestMethod]
public void Delete()
{
var id = Guid.NewGuid().ToString();
User user = new User() { ID = id, Account = "Nunit", Password = "Nunit" }; bool result = IFactory.Instance<IUserDAL>().Insert(user);
Assert.AreEqual(result, true); result = IFactory.Instance<IUserDAL>().Delete(id);
Assert.AreEqual(result, true);
}

最后我们整个单元测试的测试代码如下所示。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WHC.Framework.EF;
using EFCore.IDAL;
using EFCore.Entity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq.Expressions;
using System.Linq;
using WHC.Pager.Entity; namespace TestFrameworkEF
{
[TestClass]
public class TestBaseDAL
{
private string userId = Guid.NewGuid().ToString(); [TestInitialize]
public void Init()
{
User user = new User() { ID = userId, Account = "Nunit", Password = "Nunit" }; bool result = IFactory.Instance<IUserDAL>().Insert(user);
Assert.AreEqual(result, true);
} [TestCleanup]
public void Cleanup()
{
bool result = IFactory.Instance<IUserDAL>().Delete(userId);
Assert.AreEqual(result, true);
} [TestMethod]
public void FindByID()
{
User user = IFactory.Instance<IUserDAL>().FindByID(userId); Assert.IsNotNull(user);
Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void Insert()
{
var id = Guid.NewGuid().ToString();
User user = new User() { ID = id , Account = "Nunit", Password = "Nunit" }; bool result = IFactory.Instance<IUserDAL>().Insert(user);
Assert.AreEqual(result, true); user = IFactory.Instance<IUserDAL>().FindByID(id);
Assert.IsNotNull(user);
Assert.AreEqual(user.ID, id); result = IFactory.Instance<IUserDAL>().Delete(id);
Assert.AreEqual(result, true);
} [TestMethod]
public void InsertRang()
{
List<User> list = new List<User>();
for(int i = ; i<; i++)
{
var id = Guid.NewGuid().ToString();
User user = new User() { ID = id, Account = "Nunit" + i.ToString(), Password = "Nunit" };
list.Add(user);
} bool result = IFactory.Instance<IUserDAL>().InsertRange(list);
Assert.AreEqual(result, true); foreach(User user in list)
{
result = IFactory.Instance<IUserDAL>().Delete(user.ID);
Assert.AreEqual(result, true);
}
} [TestMethod]
public void Update()
{
string newAccount = "Test";
User user = IFactory.Instance<IUserDAL>().FindByID(userId);
user.Account = newAccount;
bool result = IFactory.Instance<IUserDAL>().Update(user, user.ID);
Assert.AreEqual(result, true); user = IFactory.Instance<IUserDAL>().FindByID(userId);
Assert.IsNotNull(user);
Assert.AreEqual(user.Account, newAccount);
} [TestMethod]
public void Delete()
{
var id = Guid.NewGuid().ToString();
User user = new User() { ID = id, Account = "Nunit", Password = "Nunit" }; bool result = IFactory.Instance<IUserDAL>().Insert(user);
Assert.AreEqual(result, true); result = IFactory.Instance<IUserDAL>().Delete(id);
Assert.AreEqual(result, true);
} [TestMethod]
public void DeleteByExpression()
{
var id = Guid.NewGuid().ToString();
User user = new User() { ID = id, Account = "Nunit", Password = "Nunit" }; bool result = IFactory.Instance<IUserDAL>().Insert(user);
Assert.AreEqual(result, true); Expression<Func<User, bool>> expression = p => p.ID == user.ID && p.Account == user.Account;
result = IFactory.Instance<IUserDAL>().DeleteByExpression(expression);
Assert.AreEqual(result, true);
} [TestMethod]
public void DeleteByCondition()
{
var id = Guid.NewGuid().ToString();
User user = new User() { ID = id, Account = "Nunit", Password = "Nunit" }; bool result = IFactory.Instance<IUserDAL>().Insert(user);
Assert.AreEqual(result, true); string condition = string.Format("ID ='{0}' ", id);
result = IFactory.Instance<IUserDAL>().DeleteByCondition(condition);
Assert.AreEqual(result, true);
} [TestMethod]
public void FindSingle()
{
Expression<Func<User, bool>> expression = p => p.ID == userId;
User dbUser = IFactory.Instance<IUserDAL>().FindSingle(expression);
Assert.IsNotNull(dbUser);
Assert.AreEqual(dbUser.ID, userId);
} [TestMethod]
public void GetQueryable()
{
User user = IFactory.Instance<IUserDAL>().GetQueryable().Take().ToList()[];
Assert.IsNotNull(user);
//Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void GetQueryableExpression()
{
Expression<Func<User, bool>> expression = p => p.ID == userId;
User user = IFactory.Instance<IUserDAL>().GetQueryable(expression, "Account").Take().ToList()[];
Assert.IsNotNull(user);
Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void GetQueryableExpression2()
{
Expression<Func<User, bool>> expression = p => p.ID == userId;
User user = IFactory.Instance<IUserDAL>().GetQueryable(expression, s=>s.Account).Take().ToList()[];
Assert.IsNotNull(user);
Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void GetAll()
{
User user = IFactory.Instance<IUserDAL>().GetAll().Take().ToList()[];
Assert.IsNotNull(user);
} [TestMethod]
public void GetAllOrderBy()
{
User user = IFactory.Instance<IUserDAL>().GetAll(s=>s.Account).Take().ToList()[];
Assert.IsNotNull(user);
} [TestMethod]
public void GetAllWithPager()
{
PagerInfo pagerInfo = new PagerInfo();
pagerInfo.PageSize = ; User user = IFactory.Instance<IUserDAL>().GetAllWithPager(pagerInfo).Take().ToList()[];
Assert.IsNotNull(user);
} [TestMethod]
public void Find()
{
Expression<Func<User, bool>> expression = p => p.ID == userId;
User user = IFactory.Instance<IUserDAL>().Find(expression).Take().ToList()[];
Assert.IsNotNull(user); Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void Find2()
{
Expression<Func<User, bool>> expression = p => p.ID == userId;
User user = IFactory.Instance<IUserDAL>().Find(expression, s=>s.Account).Take().ToList()[];
Assert.IsNotNull(user); Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void FindWithPager()
{
PagerInfo pagerInfo = new PagerInfo();
pagerInfo.PageSize = ; Expression<Func<User, bool>> expression = p => p.ID == userId; User user = IFactory.Instance<IUserDAL>().FindWithPager(expression, pagerInfo).Take().ToList()[];
Assert.IsNotNull(user); Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void FindWithPager2()
{
PagerInfo pagerInfo = new PagerInfo();
pagerInfo.PageSize = ; Expression<Func<User, bool>> expression = p => p.ID == userId; User user = IFactory.Instance<IUserDAL>().FindWithPager(expression, pagerInfo, s=>s.Account).Take().ToList()[];
Assert.IsNotNull(user); Assert.AreEqual(user.ID, userId);
} [TestMethod]
public void GetRecordCount()
{
int count = IFactory.Instance<IUserDAL>().GetRecordCount();
Assert.AreNotEqual(count, );
} [TestMethod]
public void GetRecordCount2()
{
Expression<Func<User, bool>> expression = p => p.ID == userId;
int count = IFactory.Instance<IUserDAL>().GetRecordCount(expression);
Assert.AreNotEqual(count, );
} [TestMethod]
public void IsExistRecord()
{
bool result = IFactory.Instance<IUserDAL>().IsExistRecord(userId);
Assert.AreEqual(result, true);
} [TestMethod]
public void IsExistRecord2()
{
Expression<Func<User, bool>> expression = p => p.ID == userId;
bool result = IFactory.Instance<IUserDAL>().IsExistRecord(expression);
Assert.AreEqual(result, true);
} [TestMethod]
public void SqlExecute()
{
string newAccount = "newAccount";
string sql = string.Format("update [User] set Account='{0}' Where ID='{1}' ", newAccount, userId);
int count = IFactory.Instance<IUserDAL>().SqlExecute(sql);
Assert.AreEqual(count, );
} [TestMethod]
public void SqlValueList()
{
string sql = string.Format("Select ID From [User] ");
ICollection<string> valueString = IFactory.Instance<IUserDAL>().SqlValueList(sql);
Assert.IsNotNull(valueString);
Assert.IsTrue(valueString.Count > );
}
}
}

3、运行单元测试

代码编译没有问题后,我们需要检验我们的单元测试代码的正确性,那么只需要在VS的测试菜单里面,执行下面的操作即可。

最后得到的运行结果如下所示,验证了我们基类代码的正确性。

Entity Framework 实体框架的形成之旅--为基础类库接口增加单元测试,对基类接口进行正确性校验(10)的更多相关文章

  1. Entity Framework 实体框架的形成之旅--实体数据模型 (EDM)的处理(4)

    在前面几篇关于Entity Framework 实体框架的介绍里面,已经逐步对整个框架进行了一步步的演化,以期达到统一.高效.可重用性等目的,本文继续探讨基于泛型的仓储模式实体框架方面的改进优化,使我 ...

  2. Entity Framework 实体框架的形成之旅--实体框架的开发的几个经验总结

    在前阵子,我对实体框架进行了一定的研究,然后把整个学习的过程开了一个系列,以逐步深入的方式解读实体框架的相关技术,期间每每碰到一些新的问题需要潜入研究.本文继续前面的主题介绍,着重从整体性的来总结一下 ...

  3. Entity Framework 实体框架的形成之旅--几种数据库操作的代码介绍(9)

    本篇主要对常规数据操作的处理和实体框架的处理代码进行对比,以便更容易学习理解实体框架里面,对各种数据库处理技巧,本篇介绍几种数据库操作的代码,包括写入中间表操作.联合中间表获取对象集合.递归操作.设置 ...

  4. Entity Framework 实体框架的形成之旅--界面操作的几个典型的处理(8)

    在上篇随笔<Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合>里面,介绍了在Entity Framework 实体框架里面引入了 ...

  5. Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合

    在使用Entity Framework 实体框架的时候,我们大多数时候操作的都是实体模型Entity,这个和数据库操作上下文结合,可以利用LINQ等各种方便手段,实现起来非常方便,一切看起来很美好.但 ...

  6. Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)

    在前面的随笔<Entity Framework 实体框架的形成之旅--Code First的框架设计(5)>里介绍了基于Code First模式的实体框架的经验,这种方式自动处理出来的模式 ...

  7. Entity Framework 实体框架的形成之旅--Code First的框架设计(5)

    在前面几篇介绍了Entity Framework 实体框架的形成过程,整体框架主要是基于Database First的方式构建,也就是利用EDMX文件的映射关系,构建表与表之间的关系,这种模式弹性好, ...

  8. Entity Framework 实体框架的形成之旅--基类接口的统一和异步操作的实现(3)

    在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...

  9. Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)

    在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...

随机推荐

  1. Wix 安装部署教程(十) --来,用WPF做个漂亮的安装界面

    在上一篇中曾留下两个问题,.Net捆绑安装不触发以及路径选择的问题现在都已经解决,这段时间花的最多的地方还是WPF调样式上面,奈何WPF功力不够,暂时还是没有达到自己想要的效果.另外ViewModel ...

  2. 必须知道的SQL编写技巧,多条件查询不拼字符串的写法

    在做项目中,我们经常遇到复杂的查询方法,要根据用户的输入,判断某个参数是否合法,合法的话才能当作过滤条件,我们通常的做法是把查询SQL赋值给一个字符串变量,然后根据判断条件动态的拼接where条件进行 ...

  3. redis使用心得

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com   redis是继memcached之后兴起的内存数据库,作者非常崇尚简洁高效,力求以最简单的方式最高效的解决问题 ...

  4. [安卓] 15、用NFC解锁手机并自动打开应用

    最近接到一个项目:将手机放到一个带有NFC卡的底座上手机会自动解锁,然后打开相应的应用 本人用:杭州公交通用卡做为NFC卡+Coolpad手机进行试验 效果如下: 1.手机本身带有图案锁,输对图案才能 ...

  5. iOS 获取键盘相关信息

    一,在需要的地方添加监听 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWil ...

  6. 开发者最常用的 8 款 Sublime Text 3 插件

    转载于:http://www.itxuexiwang.com/a/liunxjishu/2016/0228/177.html?1456925631Sublime Text作为一个尽为人知的代码编辑器, ...

  7. Js~对数组进行分组户数

    在sql里有group by,主要对数据结果集进行分组统计,而对于JS来说,有时我们也需要这种功能,例如一个数据{"dog","cat","dog&q ...

  8. Masonry -- 使用纯代码进行iOS应用的autolayout自适应布局

    简介 简化iOS应用使用纯代码机型自适应布局的工作,使用一种简洁高效的语法替代NSLayoutConstraints. 项目主页: Masonry 最新示例: 点击下载 项目简议: 如果再看到关于纯代 ...

  9. DELPHI支付宝支付代码

    真实业务场景的考虑 按照支付宝或者微信支付的开发手册的说法,一个标准的客户端接入支付业务模型应该是这样的,我忽略时序图,只用文字描述: 用户登录客户端,选择商品,然后点击客户端支付. 客户端收集商品信 ...

  10. pycharm运行脚本为何不生成测试报告?

    今日使用python+selenium编写自动化测试脚本并执行过程中,使用pycharm运行结果后发现脚本运行无报错,脚本中的操作也正常被执行,但就是没有生成测试报告. 为什么呢,为什么呢,生成测试报 ...