【EFCore仓储模式】介绍一个EFCore的Repository实现

news2025/1/15 13:57:57

阅读本文你的收获

  1. 了解仓储模式及泛型仓储的优点
  2. 学会封装泛型仓储的一般设计思路
  3. 学习在ASP.NET Core WebAPI项目中使用EntityFrameworkCore.Data.Repository

本文中的案例是微软EntityFrameworkCore的一个仓储模式实现,这个仓储库不是我自己写的,而是使用了一个老外写的EntityFrameworkCore.Data.Repository,大家可以一起来学习一下,如果你觉得合适,可以直接用在你的项目中,很方便。案例代码下载

一、 什么是仓储模式

仓储(Repository)模式自2004年首次作为领域驱动模型DDD设计的一部分引入,仓储本质上是提供数据的抽象,以便应用程序可以使用具有接口的相似的简单抽象集合。从此集合中CURD是通过一系列直接的方法完成,无需处理连接、命令等问题,使用此种模式可帮助实现松耦合,并保持领域对象的持久性无知。

  • 仓储模式是为了在程序的数据访问层和业务逻辑层之间创建的一个抽象层
  • 仓储模式是一种数据访问模式,提供一种更松散耦合的数据访问方法
  • 将创建数据访问的逻辑写在单独的类中即仓储
  • 仓储负责和业务层进行持久化通信

下图为控制器和仓储协同工作的图例:
仓储示意图

二、泛型仓储

仓储(Repository)是存在于工作单元和数据库之间单独分离出来的一层,是对数据访问的封装。其优点是

  • 业务层无需知道具体实现,达到分离关注点;
  • 提高对数据库访问的维护,对于仓储的改变,并不改变业务的逻辑;

如果我们采用的ORM框架是EF Core,实现仓储模式的话,那么类图设计一般如下:
仓储模式类图通常实现仓储的时候,会使用泛型技术封装增删改查的的通用功能,类型T即为具体要进行增删改查处理的实体类型。

使用泛型仓储(Generic Repository)的好处有以下几点:

  • 更好的可重用性:泛型仓储可以在多个实体类型之间共享和重用,减少了重复的代码编写和维护工作。
  • 更好的类型安全性:使用泛型仓储可以在编译时就约束数据的类型,减少了运行时类型错误的可能性。
  • 更好的简洁性:泛型仓储可以通过使用通用的方法和接口来简化数据访问的逻辑,提供统一的CRUD(增删改查)操作接口。
  • 更好的可测试性:泛型仓储使得数据访问逻辑可以更容易地进行单元测试,因为可以使用模拟或者假数据来代替实际的数据存储。
  • 更好的扩展性:泛型仓储可以通过继承或者接口实现来扩展其功能,例如添加自定义的查询方法或者过滤器。

三、基于EF Core实现的泛型仓储案例

开发环境:

操作系统: Windows 10 专业版
平台版本是:.NET 6
开发框架:ASP.NET Core WebApi、Entity Framework Core
开发工具:Visual Studio 2022
数据库: MySQL 5.7+

安装NuGet包

使用的NuGet包主要有:

  1. EntityFrameworkCore.Data.Repository – 一个老外封装好的开源EfCore仓储实现
  2. EntityFrameworkCore.Data.UnitOfWork-- 跟以上配套的工作单元
  3. Pomelo.EntityFrameworkCore.MySql – MySQL数据库提供程序

简单剖析一下 EntityFrameworkCore.Data.Repository

可以看到,作者定义了泛型仓储接口如下:

public interface IRepository<T> : IRepository, IDisposable, ISyncRepository<T>, ISyncRepository, IQueryFactory<T>, IAsyncRepository<T>, IAsyncRepository where T : class
{
}

IRepository< T >接口分别集继承了 ISyncRepository< T > 和 IAsyncRepository< T >这两个接口,分别是同步仓储方法接口和异步仓储方法接口。

//同步仓储方法接口
public interface ISyncRepository<T> : ISyncRepository, IRepository, IDisposable, IQueryFactory<T> where T : class
{
    IList<T> Search(IQuery<T> query);

    IList<TResult> Search<TResult>(IQuery<T, TResult> query);

    T SingleOrDefault(IQuery<T> query);

    TResult SingleOrDefault<TResult>(IQuery<T, TResult> query);

    T FirstOrDefault(IQuery<T> query);

    TResult FirstOrDefault<TResult>(IQuery<T, TResult> query);

    T LastOrDefault(IQuery<T> query);

    TResult LastOrDefault<TResult>(IQuery<T, TResult> query);

    bool Any(Expression<Func<T, bool>> predicate = null);

    int Count(Expression<Func<T, bool>> predicate = null);

    long LongCount(Expression<Func<T, bool>> predicate = null);

    TResult Max<TResult>(Expression<Func<T, TResult>> selector, Expression<Func<T, bool>> predicate = null);

    TResult Min<TResult>(Expression<Func<T, TResult>> selector, Expression<Func<T, bool>> predicate = null);

    decimal Average(Expression<Func<T, decimal>> selector, Expression<Func<T, bool>> predicate = null);

    decimal Sum(Expression<Func<T, decimal>> selector, Expression<Func<T, bool>> predicate = null);

    T Attach(T entity);

    void AttachRange(IEnumerable<T> entities);

    T Add(T entity);

    void AddRange(IEnumerable<T> entities);

    T Update(T entity, params Expression<Func<T, object>>[] properties);

    int Update(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> expression);

    void UpdateRange(IEnumerable<T> entities, params Expression<Func<T, object>>[] properties);

    T Remove(T entity);

    int Remove(Expression<Func<T, bool>> predicate);

    void RemoveRange(IEnumerable<T> entities);

    int ExecuteSqlCommand(string sql, params object[] parameters);

    IList<T> FromSql(string sql, params object[] parameters);

    void ChangeTable(string table);

    void ChangeState(T entity, EntityState state);

    EntityState GetState(T entity);

    void Reload(T entity);

    void TrackGraph(T rootEntity, Action<EntityEntryGraphNode> callback);

    void TrackGraph<TState>(T rootEntity, TState state, Func<EntityEntryGraphNode<TState>, bool> callback);

    IQueryable<T> ToQueryable(IQuery<T> query);

    IQueryable<TResult> ToQueryable<TResult>(IQuery<T, TResult> query);
}
//异步仓储方法接口
public interface IAsyncRepository<T> : IAsyncRepository, IRepository, IDisposable, IQueryFactory<T> where T : class
{
    Task<IList<T>> SearchAsync(IQuery<T> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<IList<TResult>> SearchAsync<TResult>(IQuery<T, TResult> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<T> SingleOrDefaultAsync(IQuery<T> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<TResult> SingleOrDefaultAsync<TResult>(IQuery<T, TResult> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<T> FirstOrDefaultAsync(IQuery<T> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<TResult> FirstOrDefaultAsync<TResult>(IQuery<T, TResult> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<T> LastOrDefaultAsync(IQuery<T> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<TResult> LastOrDefaultAsync<TResult>(IQuery<T, TResult> query, CancellationToken cancellationToken = default(CancellationToken));

    Task<bool> AnyAsync(Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<int> CountAsync(Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<long> LongCountAsync(Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<TResult> MaxAsync<TResult>(Expression<Func<T, TResult>> selector, Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<TResult> MinAsync<TResult>(Expression<Func<T, TResult>> selector, Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<decimal> AverageAsync(Expression<Func<T, decimal>> selector, Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<decimal> SumAsync(Expression<Func<T, decimal>> selector, Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<T> AddAsync(T entity, CancellationToken cancellationToken = default(CancellationToken));

    Task AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default(CancellationToken));

    Task<int> UpdateAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> expression, CancellationToken cancellationToken = default(CancellationToken));

    Task<int> RemoveAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken));

    Task<IList<T>> FromSqlAsync(string sql, IEnumerable<object> parameters = null, CancellationToken cancellationToken = default(CancellationToken));

    Task<int> ExecuteSqlCommandAsync(string sql, IEnumerable<object> parameters = null, CancellationToken cancellationToken = default(CancellationToken));

    Task ReloadAsync(T entity, CancellationToken cancellationToken = default(CancellationToken));
}
//泛型仓储的实现(列举一部分实现,感兴趣的可以自己查看源码)
public class Repository<T> : IRepository<T>, IRepository, IDisposable, ISyncRepository<T>, ISyncRepository, IQueryFactory<T>, IAsyncRepository<T>, IAsyncRepository where T : class
{
    private bool _disposed;

    protected DbContext DbContext { get; }

    protected DbSet<T> DbSet { get; }

    public Repository(DbContext dbContext)
    {
        DbContext = dbContext ?? throw new ArgumentNullException("dbContext", "dbContext cannot be null.");
        DbSet = dbContext.Set<T>();
    }

    public virtual ISingleResultQuery<T> SingleResultQuery()
    {
        return EntityFrameworkCore.QueryBuilder.SingleResultQuery<T>.New();
    }

    public virtual IMultipleResultQuery<T> MultipleResultQuery()
    {
        return EntityFrameworkCore.QueryBuilder.MultipleResultQuery<T>.New();
    }

    public virtual ISingleResultQuery<T, TResult> SingleResultQuery<TResult>()
    {
        return SingleResultQuery<T, TResult>.New();
    }

    public virtual IMultipleResultQuery<T, TResult> MultipleResultQuery<TResult>()
    {
        return MultipleResultQuery<T, TResult>.New();
    }

    public virtual IList<T> Search(IQuery<T> query)
    {
        if (query == null)
        {
            throw new ArgumentNullException("query", "query cannot be null.");
        }

        return ToQueryable(query).ToList();
    }
    public virtual T Add(T entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity", "entity cannot be null.");
        }

        DbSet.Add(entity);
        return entity;
    }

    public virtual void AddRange(IEnumerable<T> entities)
    {
        if (entities == null)
        {
            throw new ArgumentNullException("entities", "entities cannot be null.");
        }

        if (entities.Any())
        {
            DbSet.AddRange(entities);
        }
    }

    public virtual T Update(T entity, params Expression<Func<T, object>>[] properties)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity", "entity cannot be null.");
        }

        if (properties != null && properties.Any())
        {
            EntityEntry<T> entityEntry = DbContext.Entry(entity);
            foreach (Expression<Func<T, object>> propertyExpression in properties)
            {
                PropertyEntry propertyEntry;
                try
                {
                    propertyEntry = entityEntry.Property(propertyExpression);
                }
                catch
                {
                    propertyEntry = null;
                }

                if (propertyEntry != null)
                {
                    propertyEntry.IsModified = true;
                    continue;
                }

                ReferenceEntry referenceEntry;
                try
                {
                    referenceEntry = entityEntry.Reference(propertyExpression);
                }
                catch
                {
                    referenceEntry = null;
                }

                if (referenceEntry != null)
                {
                    EntityEntry targetEntry = referenceEntry.TargetEntry;
                    DbContext.Update(targetEntry.Entity);
                }
            }
        }
        else
        {
            DbSet.Update(entity);
        }

        return entity;
    }

    public virtual int Update(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> expression)
    {
        if (predicate == null)
        {
            throw new ArgumentNullException("predicate", "predicate cannot be null.");
        }

        if (expression == null)
        {
            throw new ArgumentNullException("expression", "expression cannot be null.");
        }

        return Queryable.Where(DbSet, predicate).Update(expression);
    }
public virtual T Remove(T entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity", "entity cannot be null.");
        }

        DbSet.Remove(entity);
        return entity;
    }

    public virtual int Remove(Expression<Func<T, bool>> predicate)
    {
        if (predicate == null)
        {
            throw new ArgumentNullException("predicate", "predicate cannot be null.");
        }

        return Queryable.Where(DbSet, predicate).Delete();
    }

    public virtual void RemoveRange(IEnumerable<T> entities)
    {
        if (entities == null)
        {
            throw new ArgumentNullException("entities", "entities cannot be null.");
        }

        if (entities.Any())
        {
            DbSet.RemoveRange(entities);
        }
    }

四、 在WebApi项目中使用EntityFrameworkCore.Data.Repository

  1. 在appsettings.json中配置连接字符串
//配置连接字符串
  "ConnectionStrings": {
    "default": "Server=localhost;Database=20240114WebApplication;user=root;password=12345;port=3306"
  },
  1. 在Program.cs中注册相关服务
//注册DbContext服务
string connectionString = builder.Configuration.GetConnectionString("default");
builder.Services.AddDbContext<MyDbContext>(
    option => option.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)
));
builder.Services.AddScoped<DbContext, MyDbContext>();

// 注册工作单元
builder.Services.AddUnitOfWork();
//builder.Services.AddUnitOfWork<MyDbContext>(); // 多数据库支持
//注册泛型仓储服务
builder.Services.AddScoped(typeof(Repository<>));

  1. 设计实体类,本例图书管理为例
 public class Book
 {
     public Book()
     {
         Title = string.Empty;
         ISBN = string.Empty;
     }

     [Key]
     public long Id { get; set; }

     [Required]
     [MaxLength(100)]
     public string Title { get; set; }

     [Required]
     [MaxLength(20)]
     public string ISBN { get; set; }

     public long CategoryId { get; set; }

     //导航属性
     [ForeignKey("CategoryId")]
     public virtual Category Category { get; set; }
 }

public class Category
{
    public Category()
    {
        Name = string.Empty;
        Code = string.Empty;
    }

    [Key]
    public long Id { get; set; }

    /// <summary>
    /// 分类代码
    /// </summary>
    [Required]
    [MaxLength(30)]
    public string Code { get; set; }

    /// <summary>
    /// 分类名
    /// </summary>
    [Required]
    [MaxLength(30)]
    public string Name { get; set; }

    //导航属性
    public virtual IList<Book> Books { get; set; }
}
  1. 实现图书管理API接口

(1)依赖注入泛型仓储和工作单元对象:

[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
    //泛型仓储
    private readonly Repository<Book> _bookRepository;
    private readonly Repository<Category> _categoryRepository;
    //工作单元
    private readonly IUnitOfWork _unitOfWork;

    //构造方法
    public BooksController(Repository<Book> bookRepository,
                           Repository<Category> categoryRepository,
                           IUnitOfWork unitOfWork)
    {
        _bookRepository = bookRepository;
        _categoryRepository = categoryRepository;
        _unitOfWork = unitOfWork;
    }
}

(2)实现分页显示:

  //分页查询(使用Include加载导航属性)
  [HttpGet("GetPageList")]
  public async Task<ActionResult<IPagedList<BookOutput>>> GetPageList([FromQuery] BookPageRequestInput input)
  {
      //创建查询对象-MultipleResultQuery表示多结果集查询
      var query = _bookRepository.MultipleResultQuery<BookOutput>()
                        .Page(input.PageIndex, input.PageSize) //分页
                        .AndFilter(b => string.IsNullOrEmpty(input.Title) || b.Title.StartsWith(input.Title)) //筛选条件
                        .Include(q => q.Include(x => x.Category))  //级联加载
                        .OrderByDescending("Title").ThenBy("ISBN") //排序
                        .Select(b => new BookOutput                //投影
                        {
                            CategoryId = b.CategoryId,
                            CategoryCode = b.Category.Code,
                            CategoryName = b.Category.Name,
                            ISBN = b.ISBN,
                            Title = b.Title,
                            Id = b.Id
                        }) as IMultipleResultQuery<Book, BookOutput>; //转换类型

      //执行查询
      var result = (await _bookRepository.SearchAsync(query))
                           .ToPagedList(query.Paging.PageIndex,
                                      query.Paging.PageSize,
                                      query.Paging.TotalCount);

      return Ok(result);
  }
  //分页查询(使用IQueryable.Join方法进行联表查询)
  [HttpGet("GetBookPage")]
  public async Task<ActionResult<PagedList<BookOutput>>> GetBookPage([FromQuery] BookPageRequestInput input)
  {
      //获取可IQueryable可查询对象
      var books = _bookRepository.ToQueryable(_bookRepository.MultipleResultQuery());
      var categories = _categoryRepository.ToQueryable(_categoryRepository.MultipleResultQuery());
      
      var query = books.Join(categories, b => b.CategoryId, c => c.Id,
                     (b, c) => new BookOutput
                     {
                         CategoryId = b.CategoryId,
                         CategoryCode = b.Category.Code,
                         CategoryName = b.Category.Name,
                         ISBN = b.ISBN,
                         Title = b.Title,
                         Id = b.Id
                     })
                     .Where(b => string.IsNullOrEmpty(input.Title) || b.Title.StartsWith(input.Title))
                     .OrderBy(b => b.Id);
      
      PagedList<BookOutput> result = new PagedList<BookOutput>();
      result.TotalCount = await query.CountAsync();
      result.Items = await query.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToListAsync();

      return result;
  }

(3)添加图书:

  //POST api/Books
  [HttpPost]
  public async Task<ActionResult<int>> Add([FromBody] BookAddOrUpdateInput input)
  {
      Book book = new Book
      {
          CategoryId = input.CategoryId,
          ISBN = input.ISBN,
          Title = input.Title
      };

      await _bookRepository.AddAsync(book);
      var result = await _unitOfWork.SaveChangesAsync();

      return result;
  }

(4)修改图书:

   //PUT api/Books
   [HttpPut]
   public async Task<ActionResult<int>> Update([FromBody] BookAddOrUpdateInput input)
   {
       var numAffected = await _bookRepository.UpdateAsync(b => b.Id == input.Id, b => new Book
       {
           CategoryId = input.CategoryId,
           ISBN = input.ISBN,
           Title = input.Title
       });

       var result = await _unitOfWork.SaveChangesAsync();

       return result;
   }

(5)删除图书:

   //DELETE api/Books/{id}
   [HttpDelete("{id}")]
   public async Task<ActionResult<int>> Delete(long id)
   {
       var numAffected = await _bookRepository.RemoveAsync(b => b.Id == id);

       var result = await _unitOfWork.SaveChangesAsync();

       return result;
   }

(6)根据ID获取图书:

  //GET api/Books/{id}
  [HttpGet("{id}")]
  public async Task<ActionResult<BookOutput>> Get(long id)
  {
      //创建查询对象,SingleResultQuery表示单条结果查询
      var query = _bookRepository.SingleResultQuery<BookOutput>()
                        .Include(q => q.Include(x => x.Category))
                        .AndFilter(b => b.Id == id)
                        .Select(b => new BookOutput  //投影
                        {
                            CategoryId = b.CategoryId,
                            CategoryCode = b.Category.Code,
                            CategoryName = b.Category.Name,
                            ISBN = b.ISBN,
                            Title = b.Title,
                            Id = b.Id
                        });

      return await _bookRepository.SingleOrDefaultAsync(query);
  }

本次演示了在ASP.NET Core中使用泛型仓储模式封装EF Core的CRUD方法,推荐大家可以尝试一下EntityFrameworkCore.Data.Repository这个开源仓储实现类。如果本文对你有帮助的话,请点赞+评论+关注,或者转发给需要的朋友。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1399373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口自动化框架搭建-写在前面

从今天开始&#xff0c;我将带领大家一起学习接口自动化框架的搭建&#xff0c;在学习之前&#xff0c;我们先了解搭建一个接口自动化框架需要具备哪些知识&#xff0c;应该做哪些准备工作 测试开发工程师的入门条件 近几年比较流行测试开发岗位&#xff0c;很多小伙伴都不知…

虚拟机安装宝塔的坑

问题&#xff1a; 在虚拟机中centos7和centos8中安装宝塔之后&#xff0c;无法访问面板。 解决&#xff1a; 1.先关闭防火墙&#xff08;如果本机能够ping通相关端口&#xff0c;则不用关闭防火墙&#xff09; 2.最新的宝塔会自动开启ssl协议&#xff0c;需要手动关闭。…

【深度学习】BasicSR训练过程记录

文章目录 两种灵活的使用场景项目结构概览简化的使用方式 项目结构解读1. 代码的入口和训练的准备工作2. data和model的创建2.1 dataloader创建2.2 model的创建 3. 训练过程 动态实例化的历史演进1. If-else判断2. 动态实例化3. REGISTER注册机制 REGISTER注册机制的实现1. DAT…

反序列化提升刷题(2)

今天的例题&#xff1a; <?phphighlight_file(__FILE__);class ctfshowvip{public $username;public $password;public $code;public function __construct($u,$p){$this->username$u;$this->password$p;}public function __wakeup(){if($this->username! || $thi…

2008年苏州大学837复试机试C语言

2008年苏州大学复试机试C 题目 编写程序充成以下功能: 一、从键盘上输入随机变量x的 10个取样点。X0&#xff0c;X1—X9 的值; 1、计算样本平均值 2、判定x是否为等差数列 3、用以下公式计算z的值(t0.63) 注。请对程序中必要地方进行注释 补充&#xff1a;个人觉得这个题目回…

macOS修改默认时区显示中国时间

默认时区不是中国,显示时间不是中国时间 打开终端 ,删除旧区,并复制新时区到etcreb sudo -rm -rf /etc/localtime sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 重启系统后时间显示为中国时间

R 语言学习 case3:柱状图(ggchart)

主要涉及到对图的优化&#xff0c;使用ggchart工具包 ggchart 链接&#xff1a;https://thomas-neitmann.github.io/ggcharts/index.html step1: 安装工具包 install.packages("ggcharts") install.packages("tidytext")step2: 导入工具包 library(dplyr…

【游戏开发程序员必备技术】

【游戏开发程序员必备技术】 当你披着《英雄联盟》的战袍&#xff0c;挥舞着利剑&#xff0c;与对手不死不休地战斗&#xff1b; 当你驾驶着战车穿过《坦克世界》的烟尘弹雨&#xff0c;掩护基地免受敌人侵袭&#xff1b; 当你完美落地《CS&#xff1a;GO》的翻墙smoke&…

领航分布式消息系统:一起探索Apache Kafka的核心术语及其应用场景

本文是Kafka系列文章的第一篇&#xff0c;将带你了解Kafka的核心术语及其应用场景&#xff0c;后续会逐步探索其各方面的原理及应用场景。下面先看一张大概得简图&#xff0c;涉及Kafka的功能、原理等等&#xff0c;后续不断深入介绍&#xff0c;欢迎关注。 1、什么是消息中间…

unity 编辑器开发一些记录(遇到了更新)

1、封装Toggle组件 在用toggle等会状态改变的组件时&#xff0c;通过select GUILayout.Toggle(select, text, options)通常是这样做&#xff0c;但是往往有些复杂编辑器需求&#xff0c;当select变化时需要进行复杂的计算&#xff0c;所以不希望每帧去计算select应该的信息。…

muduo 网络库源码解析和使用

1. base 模块 1.1 API 1.1.1 eventfd int eventfd(unsigned int initval, int flags);&#xff08;1&#xff09;类似信号量&#xff1b;其内部保存了一个 uint64_t 计数器 count&#xff0c;使用 initval 初始化&#xff1b; &#xff08;2&#xff09;read 没有设置 EFD…

uniapp-app视频层级过高问题

使用v-html动态渲染 参考&#xff1a;uniapp video app端层级过高的问题&#xff0c;滑动渲染问题。_video在app端层级过高-CSDN博客 有想过使用原生&#xff0c;但是太麻烦了&#xff0c;然后换成了弹窗播放&#xff0c;但是动态的src播放失败&#xff0c;错误提示&#xff…

洋州影院购票系统:如何用Java、Spring Boot、Vue和MySQL实现现代化管理

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

【高等数学之牛莱公式】

一、深入挖掘定积分 二、变限积分 三、变限积分的"天然"连续性 四、微积分基本定理 五、定积分基本方法 5.1、换元法 5.2、分部积分法 六、定积分经典结论 七、区间再现公式 八、三角函数积分变换公式 九、周期函数积分变换公式 十、分段函数求定积分

【MySQL】——关系数据库标准语言SQL(大纲)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

HCIA——18实验:NAT

学习目标&#xff1a; NAT 学习内容&#xff1a; NAT 1.要求——基本的 2.模型 3.IP分配、规划、优化 1&#xff09;思路 R2为ISP路由器&#xff0c;其上只能配置ip地址&#xff0c;不得冉进行其他的任何配置—ospf配置 认证 、汇总、沉默接口、加快收敛、缺省路由 PC1-PC2…

如何通过frp、geoserver发布家里电脑的空间数据教程

如何通过家里电脑的geoserver发布空间数据的教程 简介 大家好&#xff0c;我是锐多宝&#xff0c;最近我在开发一个新网站的时候遇到一个需求&#xff0c;这里记录一下以帮助需要用到的网友。 我的需求是&#xff1a;用户通过网站前端上传空间数据后&#xff0c;即可在前端展…

【Spring 篇】MyBatis核心配置文件解密:数据之门的守护精灵

欢迎来到MyBatis的幕后花絮&#xff0c;今天我们将深入解析MyBatis的核心配置文件&#xff0c;这个神秘的数据之门的守护精灵。这份配置文件是连接你的应用程序和数据库之间的纽带&#xff0c;也是整个MyBatis舞台背后的幕后工作者。在这篇博客中&#xff0c;我们将揭开核心配置…

竞赛保研 机器学习股票大数据量化分析与预测系统 - python 竞赛保研

文章目录 0 前言1 课题背景2 实现效果UI界面设计web预测界面RSRS选股界面 3 软件架构4 工具介绍Flask框架MySQL数据库LSTM 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器学习股票大数据量化分析与预测系统 该项目较为新颖&am…

Cortex-M3/M4内核中断及HAL库函数详解(1):中断相关寄存器

0 工具准备 Keil uVision5 Cortex M3权威指南&#xff08;中文&#xff09; Cortex M3与M4权威指南 stm32f407的HAL库工程 STM32F4xx中文参考手册 1 NVIC相关寄存器介绍 在Cortex-M3/M4内核上搭载了一个异常响应系统&#xff0c;支持为数众多的系统异常和外部中断。其中&#…