ASP.Net Core基于EF6、Unitwork、Autofac实现Repository模式

这是一篇关于在 ASP.Net Core 中应用 Repository 模式的攻略。我们将使用 Entity Framework 6,以及 UnitOfWork 模式和 Autofac 依赖注入框架来实现它。下面将是具体的步骤:

准备工作

在继续之前,我们需要确保在系统中安装了以下软件:

  • Visual Studio 2017 及以上版本
  • .NET Core SDK 及以上版本
  • Entity Framework 6.2 及以上版本

创建项目

首先我们需要新建一个 ASP.Net Core Web 应用程序。我们可以选择在 Visual Studio 2017 中使用 “ASP.Net Core Web 应用程序” 模板来创建。选择 Web 应用程序模板后,我们需要选择 ASP.Net Core 的版本以及项目的类型(例如 Web API 或 MVC)。

安装 NuGet 包

在创建完项目后,我们需要安装一些 NuGet 包。打开 NuGet 包管理器控制台并运行以下命令:

Install-Package EntityFramework
Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection
Install-Package Autofac.Extras.DynamicProxy
Install-Package Microsoft.EntityFrameworkCore.SqlServer

这些命令将安装 Entity Framework、Autofac 及其相关插件以及 SQL Server 数据库提供程序。

创建仓储接口

接下来我们需要创建一个仓储接口,该接口定义了一些标准的 CRUD 操作。在本教程中,我们将创建一个名为 IRepository 的接口。我们可以在项目中创建一个名为 “Repositories” 的文件夹,然后在该文件夹下创建一个接口文件:

public interface IRepository<TEntity> where TEntity : class
{
    TEntity GetById(int id);
    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

在这个例子中,我们定义了四个基本的操作,并使用泛型来确保我们能够处理任何实体类型。

实现仓储接口

接下来我们需要实现 IRepository 接口。在本教程中,我们将使用 Entity Framework 6 数据访问技术实现这个接口。我们可以在项目中创建一个名为 “Repositories” 的文件夹,然后在该文件夹下创建一个名为 EfRepository 的类,该类将实现 IRepository 接口:

public class EfRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly DbContext _dbContext;

    public EfRepository(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public TEntity GetById(int id)
    {
        return _dbContext.Set<TEntity>().Find(id);
    }

    public void Insert(TEntity entity)
    {
        _dbContext.Set<TEntity>().Add(entity);
    }

    public void Update(TEntity entity)
    {
        _dbContext.Set<TEntity>().Attach(entity);
        _dbContext.Entry(entity).State = EntityState.Modified;
    }

    public void Delete(TEntity entity)
    {
        _dbContext.Set<TEntity>().Remove(entity);
    }
}

在这个例子中,我们创建了一个名为 EfRepository 的类来实现 IRepository 接口。我们使用 Entity Framework 中的 DbContext 类来管理数据库连接和操作实体。在构造函数中,我们将 DbContext 通过构造函数注入到仓储实现中。

实现 UnitOfWork

现在我们需要创建一个名为 IUnitOfWork 的接口,该接口定义了一个 SaveChanges 方法,并在其内部使用事务来确保数据的完整性。我们可以在项目中创建一个名为 “UnitOfWorks” 的文件夹,然后在该文件夹下创建一个接口文件:

public interface IUnitOfWork : IDisposable
{
    void SaveChanges();
}

在这个例子中,我们定义了 IUnitOfWork 接口,并指定了一个 SaveChanges 方法,该方法将确保在一个事务内提交所有待提交的更改。

接下来,我们需要一个具体的 UnitOfWork 类来实现 IUnitOfWork 接口。我们可以在项目中的名为 “UnitOfWorks” 的文件夹下创建一个名为 EfUnitOfWork 的类,代码如下:

public class EfUnitOfWork : IUnitOfWork
{
    private readonly DbContext _dbContext;
    private readonly ILifetimeScope _lifetimeScope;
    private readonly IDictionary<Type, object> _repositories;

    public EfUnitOfWork(DbContext dbContext, ILifetimeScope lifetimeScope)
    {
        _dbContext = dbContext;
        _lifetimeScope = lifetimeScope;
        _repositories = new Dictionary<Type, object>();
    }

    public void SaveChanges()
    {
        using (var transaction = _dbContext.Database.BeginTransaction())
        {
            try
            {
                _dbContext.SaveChanges();

                foreach (var repository in _repositories.Values)
                {
                    ((dynamic) repository).Commit();
                }

                transaction.Commit();
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
            finally
            {
                foreach (var repository in _repositories.Values)
                {
                    ((IDisposable) repository).Dispose();
                }

                _repositories.Clear();
                _dbContext.Dispose();
            }
        }
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        if (!_repositories.ContainsKey(typeof(TEntity)))
        {
            var repository = _lifetimeScope.Resolve<IRepository<TEntity>>();
            _repositories.Add(typeof(TEntity), repository);
        }

        return (IRepository<TEntity>) _repositories[typeof(TEntity)];
    }

    private bool _disposed;

    public virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _dbContext.Dispose();
            }

            _disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

在这个例子中,我们创建了一个基于 Entity Framework 的 EfUnitOfWork 类来实现我们定义的 IUnitOfWork 接口。在构造函数中,我们将 DbContext 和 Autofac 的 ILifetimeScope 通过构造函数注入到了 EfUnitOfWork 类中。此外,我们还为每个类型创建了一个仓储对象。在 SaveChanges 方法中,我们开始一个新的事务,并处理所有等待提交的更改。在成功提交更改后,我们将调用每个仓储的 Commit 方法来确保所有数据都已保存。

实现依赖注入

现在我们需要设置依赖注入来确保我们的 EfRepositoryEfUnitOfWork 类能够被正确地注入到其他类中。为此,我们需要在 ConfigureServices 方法中做以下两件事情:

  1. 注册依赖项
  2. 设置 MVC 控制器解析

请注意,我们需要为 DbContextIUnitOfWork 接口设置生命周期为“请求”,以确保在 HTTP 请求期间使用的所有组件都具有相同的依赖项。这将确保所有组件都使用相同的数据库上下文对象,并在 HTTP 请求结束时确保它被销毁。我们可以通过以下方式来配置依赖注入:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddDbContext<MyDbContext>(options =>
    {
        options.UseSqlServer(Configuration.GetConnectionString("MyDbContext"));
    }, ServiceLifetime.Scoped);

    services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));

    services.AddScoped<IUnitOfWork, EfUnitOfWork>();

    services.AddControllers().AddControllersAsServices().AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.IgnoreNullValues = true;
    });

    // ...
}

在这个例子中,我们首先为 DbContext 注册一个 SQL Server 数据库提供程序。我们在这里使用了 AddDbContext 方法,该方法将被发送到 IServiceCollection,从而确保在请求期间只有一个 SQL Server 数据库实例存在。此外,我们还将 IRepositoryIUnitOfWork 接口注册为 Scoped 生存期,以确保它们在 HTTP 请求内部具有相同的生存期,只有在请求结束时才会被销毁。

注入仓储和工作单元

现在我们已经设置好了依赖注入,所以我们可以注入我们的仓储接口和工作单元接口到我们的代码中。例如,假设我们已经创建了一个名为 MyService 的类,在这个类中我们需要使用一个仓储:

public class MyService
{
    private readonly IRepository<MyEntity> _repository;
    private readonly IUnitOfWork _unitOfWork;

    public MyService(IRepository<MyEntity> repository, IUnitOfWork unitOfWork)
    {
        _repository = repository;
        _unitOfWork = unitOfWork;
    }

    public void DoSomething()
    {
        var entity = new MyEntity { Name = "John Doe" };

        _repository.Insert(entity);

        _unitOfWork.SaveChanges();
    }
}

在这个例子中,我们已经注入了一个 IRepository<MyEntity> 对象和一个 IUnitOfWork 对象到 MyService 类中。

示例说明

下面将给出两个示例说明,以便更好地理解本教程中所描述的概念。

示例 1:使用仓储

首先,我们将使用 MyService 类中注入的 IRepository<MyEntity> 对象实现一些数据访问示例:

public class MyController : Controller
{
    private readonly IRepository<MyEntity> _repository;

    public MyController(IRepository<MyEntity> repository)
    {
        _repository = repository;
    }

    public IActionResult GetById(int id)
    {
        var entity = _repository.GetById(id);

        if (entity != null)
        {
            return Ok(entity);
        }

        return NotFound();
    }

    public IActionResult Create()
    {
        var entity = new MyEntity { Name = "John Doe" };

        _repository.Insert(entity);

        return Ok();
    }
}

在这个示例中,我们创建了一个名为 MyController 的 ASP.Net Core 控制器来处理两个请求。 GetById 请求接受一个参数 id,并使用 IRepository<MyEntity> 中的 GetById 方法查找具有这个 ID 的实体。 如果找到了,就返回一个包含字符串表示的 MyEntity 对象。否则返回 404 未找到错误。

另一个动作是 Create,它创建一个新的 MyEntity 对象并插入数据库。在这个例子中,我们使用 IRepository<MyEntity>Insert 方法来操作数据。

示例 2:使用工作单元

现在我们将实现一个需要使用工作单元来确保数据完整性的功能。假设我们需要在数据库中创建一个需要提交多个更改才能保持完整性的实体。在这种情况下,我们将使用 IUnitOfWork 接口和 EfUnitOfWork 类中的 SaveChanges 方法。

下面是一个使用 IUnitOfWork 接口的示例:

public class MyController : Controller
{
    private readonly IRepository<MyEntity> _repository;
    private readonly IUnitOfWork _unitOfWork;

    public MyController(IRepository<MyEntity> repository, IUnitOfWork unitOfWork)
    {
        _repository = repository;
        _unitOfWork = unitOfWork;
    }

    public IActionResult CreateComplexEntity()
    {
        var entity1 = new MyEntity { Name = "John Doe" };
        var entity2 = new MyEntity { Name = "Jane Doe" };
        var entity3 = new MyComplexEntity
        {
            Entity1 = entity1,
            Entity2 = entity2
        };

        _repository.Insert(entity1);
        _repository.Insert(entity2);
        _repository.Insert(entity3);

        _unitOfWork.SaveChanges();

        return Ok();
    }
}

在这个示例中,我们创建了一个名为 CreateComplexEntity 的 ASP.Net Core 控制器动作,该动作将创建一个包含两个实体的复合实体并将它们全部插入数据库。在这个例子中,我们需要在 IUnitOfWork 接口上调用 SaveChanges 方法,这将确保在事务内提交所有更改。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:ASP.Net Core基于EF6、Unitwork、Autofac实现Repository模式 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • 基于C#实现网络爬虫 C#抓取网页Html源码

    下面是“基于C#实现网络爬虫 C#抓取网页Html源码”的完整攻略: 一、网络爬虫简介 网络爬虫,也称为网络蜘蛛、网络机器人等,是一种自动化的程序,用于在互联网上通过各种方式获取信息。 二、C#抓取网页Html源码 1. 使用C#自带的WebClient类 C#自带的WebClient类可以轻松地访问网页,并将其HTML源码下载到本地。下面是一个示例代码: …

    C# 2023年6月6日
    00
  • ASP.NET Core Middleware的实现方法详解

    ASP.NET Core Middleware的实现方法详解 在ASP.NET Core中,中间件是一种用于处理HTTP请求和响应的组件。我们可以使用中间件来记录接口的耗时,以便我们可以更好地了解的应用程序的性能。在本攻略中,我们将介绍如何编写一个中间件记录接口的耗时,并提供两示例说明。 实现步骤 以下是在ASP.NET Core中编写一个中间件来记录接口耗…

    C# 2023年5月16日
    00
  • C#实现无限级联下拉列表框

    下面是详细讲解“C#实现无限级联下拉列表框”的完整攻略: 1.准备工作 首先,我们需要在C#中创建一个Windows Forms应用程序。然后,在程序中创建一个ComboBox控件,作为第一级下拉列表框。同时,我们还需要准备一个数据表,用于存储下拉列表框的数据源。 2.绑定数据源 接下来,我们需要将数据表绑定到ComboBox控件中,这里可以使用DataSo…

    C# 2023年5月31日
    00
  • asp.net 中将表单提交到另一页 Code-Behind(代码和html在不同的页面)

    要将表单提交到另一页Code-Behind中,需要执行以下步骤: 1. 设置HTML表单 在HTML页面中,设置表单的提交属性为“POST”,方法属性设置为“server”,并在表单中添加所需的输入元素。 <!DOCTYPE html> <html lang="en"> <head> <meta …

    C# 2023年5月31日
    00
  • C#获取哈希加密生成随机安全码的类实例

    获取哈希加密生成随机安全码的类实例,可以使用C#的内置类库System.Security.Cryptography中的类MD5、SHA1、SHA256等类。以下是详细的攻略流程: 1.导入System.Security.Cryptography命名空间 在C#中使用加密算法需要导入System.Security.Cryptography命名空间。首先在代码中…

    C# 2023年6月8日
    00
  • C#实现的滚动网页截图功能示例

    C#实现滚动网页截图功能攻略 1. 概述 滚动截图是一种常见的网页截图技术,它可以将整个页面的截图多次拼接在一起,形成完整的网页截图。本文将介绍通过C#编写实现滚动网页截图功能。 2. 实现思路 使用WebBrowser控件作为载体,在WebBrowser控件中载入网页,通过Javascript将网页的滚动条滚动到底部,将页面的高度计算出来。 将WebBro…

    C# 2023年6月6日
    00
  • C# 动态加载程序集信息

    C# 动态加载程序集信息是指在程序运行中,动态地从文件系统或网络中加载程序集信息,然后使用反射技术获取程序集中的类型信息并进行调用。这种动态加载程序集信息的方法通常用于实现插件式架构、程序集延迟加载等功能。 实现C# 动态加载程序集信息的步骤如下: 加载程序集 使用Assembly.Load方法,可以从文件系统或网络中加载程序集。如下面的代码: Assemb…

    C# 2023年6月1日
    00
  • 浅谈C#各种数组直接的数据复制/转换

    浅谈C#各种数组之间的数据复制/转换 在C#中,数组的复制和转换是开发中经常遇到的任务。对于不同类型的数组之间的复制和转换,有不同的方法。本篇文章将详细介绍C#中多种数组之间的数据复制和转换。 一、同类型数组的复制 1.1 直接使用复制方法 C#中同类型数组可以直接使用Array类的Copy方法实现数组数据的复制。 示例代码: int[] arr1 = ne…

    C# 2023年6月7日
    00
合作推广
合作推广
分享本页
返回顶部