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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xianglikai1/article/details/79305068

年关将至,事情也少了许多,虽然接触过些三层结构的项目,但是一直没有自己从头到尾仔细写过,很多东西还是模模糊糊,这次花费了几天时间从头到尾的写出了这样一个小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>
        /// <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。

展开阅读全文

没有更多推荐了,返回首页