您的位置:首页 > 编程语言 > C#

.NET C#三层开发结构Demo详解及源码(一)

2018-02-10 15:35 519 查看
年关将至,事情也少了许多,虽然接触过些三层结构的项目,但是一直没有自己从头到尾仔细写过,很多东西还是模模糊糊,这次花费了几天时间从头到尾的写出了这样一个小Demo,在这将流程记录下来,为我以后可以更方便的复习,也希望能帮助到一些朋友。
项目划分为Model,IDAL,IBLL,DAL,BLL,WebUI,数据库为SQL Server,数据访问使用EntityFramework5.0,使用了简单工厂,单例,抽象工厂,实现类库的装载使用反射+配置文件的方式,将编译时改为运行时。
好处:
1.可以并行开发,提高开发效率;
2.不局限数据库,可低成本的更换数据库;
3.代码重用,一个数据访问层可供多个业务逻辑层,一个业务逻辑层可将数据供到多个表现形式;
4.耦合度降低,模块之间依赖小,可插卸的模块,维护简单,更新轻松,BUG定位更准确;
5.应该还有吧,暂时想不到了....
源码已发布到码云:https://gitee.com/xianglikai1/CSharpSanCengKaiFaDemo
三层结构:数据访问层,业务逻辑层,表现层,而本项目结构如下:
Model:数据实体模型
IDAL:数据访问接口描述
IBLL:业务逻辑接口描述
TestDAL:数据访问接口的实现类库
TestBLL:业务逻辑接口的实现类库
WebUI:Web表现层



数据库使用了两个表,Users和Nation,结构如下:



Model层,使用EntityFramework5.0,添加了一个扩展类文件



ExtendModel.cs代码using System.Data.Entity;
using System.Linq;

namespace Model
{
//全部扩展实体类属性

public partial class Users
{
private DbContext context = new Test1DbContext();
public string NationName
{
get { return context.Set<Nation>().Where(r => r.NationCode == this.NationCode).First().NationName; }
}

public string SexStr
{
get { return this.Sex == true ? "男" : "女"; }
}
}
}IDAL数据访问接口描述,此类库需引用Model,包含一个基础接口,两个实体类操作接口,一个工厂;



IBaseIDAL.cs 基础接口代码using System;
using System.Linq;
using System.Linq.Expressions;

namespace IDAL
{
/// <summary>
/// 数据访问基础描述接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IBaseIDAL<T> where T : class
{
IQueryable<T> Select();

IQueryable<T> Select(Expression<Func<T, bool>> exp);

T Select(int key);

int Insert(T entity);

int Update(T entity);

int Delete(T entity);
}
}IUsersIDAL.cs 和 INationIDAL.cs 实体类操作接口代码
using System.Linq;
using Model;

namespace IDAL
{
public interface IUsersIDAL : IBaseIDAL<Users>
{
//扩展方法描述写在这里

/// <summary>
/// 扩展分页方法
/// </summary>
/// <param name="PageSize"></param>
/// <param name="PageIndex"></param>
/// <returns></returns>
IQueryable<Users> Select(int PageSize, int PageIndex);
}
}
using Model;

namespace IDAL
{
public interface INationIDAL:IBaseIDAL<Nation>
{
//扩展方法描述写在这里
}
}
DALFactory.cs 工厂类代码,使用反射与配置文件装载实现类库及对象,同时降低对外的使用难度using System.Configuration;
using System.Reflection;
using Model;

namespace IDAL
{
/// <summary>
/// 数据访问类泛型工厂
/// </summary>
/// <typeparam name="T">需要操作的Model实体类型</typeparam>
public class DALFactory<T>
{
private static readonly string DAL_NameSpace = ConfigurationManager.AppSettings["DAL_NameSpace"];
private static readonly string DAL_Users = ConfigurationManager.AppSettings["DAL_Users"];
private static readonly string DAL_Nation = ConfigurationManager.AppSettings["DAL_Nation"];

public dynamic CreateDAL()
{
if (typeof(T) == typeof(Users))
return Assembly.Load(DAL_NameSpace).CreateInstance(DAL_NameSpace + "." + DAL_Users) as IUsersIDAL;
else if (typeof(T) == typeof(Nation))
return Assembly.Load(DAL_NameSpace).CreateInstance(DAL_NameSpace + "." + DAL_Nation) as INationIDAL;

return null;
}
}
}
TestDAL数据访问接口实现,需引用Model和IDAL,但自身是动态装载



DbContextFactory.cs 数据上下文单例工厂代码using System.Data.Entity;
using Model;

namespace TestDAL
{
/// <summary>
/// 上下文对象单例工厂
/// </summary>
public class DbContextFactory
{
private static DbContext _Test1Context;

public static DbContext Test1Context
{
get
{
if (_Test1Context == null) _Test1Context = new Test1DbContext();
return _Test1Context;
}
}
}
}
BaseDAL.cs 数据访问基础接口的实现类,不用在去每个具体的数据访问类中实现重复的方法using System;
using System.Linq;
using System.Linq.Expressions;
using IDAL;
using System.Data.Entity;

namespace TestDAL
{
/// <summary>
/// 数据访问基础接口实现
/// </summary>
public abstract class BaseDAL<T> : IBaseIDAL<T> where T : class
{
protected DbContext context = DbContextFactory.Test1Context;
public int Delete(T entity)
{
context.Set<T>().Remove(entity);
return context.SaveChanges();
}

public int Insert(T entity)
{
context.Set<T>().Add(entity);
return context.SaveChanges();
}

public IQueryable<T> Select()
{
return context.Set<T>();
}

/// <summary>
/// 主键匹配
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public abstract Expression<Func<T, bool>> GetByKey(int key);

public T Select(int key)
{
return context.Set<T>().Where(GetByKey(key)).FirstOrDefault();
}

public IQueryable<T> Select(Expression<Func<T, bool>> exp)
{
return context.Set<T>().Where(exp);
}

public int Update(T entity)
{
context.Set<T>().Attach(entity);
context.Entry(entity).State = System.Data.EntityState.Modified;
return context.SaveChanges();
}
}
}
UsersDAL.cs 和 NationDAL.cs 的具体实现类代码using System;
using Model;
using IDAL;
using System.Linq;
using System.Linq.Expressions;

namespace TestDAL
{
/// <summary>
/// Users数据访问类
/// </summary>
public class UsersDAL : BaseDAL<Users>, IUsersIDAL
{
/// <summary>
/// 重写主键匹配抽象方法
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public override Expression<Func<Users, bool>> GetByKey(int key)
{
return r => r.Ids == key;
}

/// <summary>
/// 扩展分页方法实现
/// </summary>
/// <param name="PageSize"></param>
/// <param name="PageIndex"></param>

b175
/// <returns></returns>
public IQueryable<Users> Select(int PageSize, int PageIndex)
{
return context.Set<Users>().Skip((PageIndex - 1) * PageSize).Take(PageSize);
}

}
}
using System;
using Model;
using IDAL;
using System.Linq.Expressions;

namespace TestDAL
{
public class NationDAL : BaseDAL<Nation>, INationIDAL
{
/// <summary>
/// 重写主键匹配抽象方法
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public override Expression<Func<Nation, bool>> GetByKey(int key)
{
return r => r.NationCode == ("N" + key.ToString("000"));
}
}
}
目前Model,IDAL,DAL三部分都完成了,流程为
IDAL的作用是为了解耦,IDAL提供Model的数据访问操作接口描述,DAL来实现IDAL,IDAL里的工厂又通过运行时的方式加载DAL,并简化外部使用的程度,实现并行开发,同时将更换数据库的工作降到最低,减少BUG率。
下篇来写IBLL、BLL、WebUI。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: