From 8d7b119c5f13b587b8328900b810317b92747266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E9=B8=A3=E6=9D=B0?= <2958949458@qq.com> Date: Sun, 9 Jun 2024 22:30:44 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=94=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...350\200\205Dto\345\206\231\346\263\225.md" | 157 ++++++++++++++++++ ...76\344\271\246\351\203\250\345\210\206.md" | 153 +++++++++++++++++ ...0240606_EFCore\347\256\200\344\273\213.md" | 33 ++++ ...re\347\232\204\344\275\277\347\224\250.md" | 120 +++++++++++++ 4 files changed, 463 insertions(+) create mode 100644 "\351\222\237\351\270\243\346\235\260/20240603_\351\241\271\347\233\256\345\256\236\347\216\260--\344\275\234\350\200\205Dto\345\206\231\346\263\225.md" create mode 100644 "\351\222\237\351\270\243\346\235\260/20240605_\351\241\271\347\233\256\345\256\236\347\216\260--\345\233\276\344\271\246\351\203\250\345\210\206.md" create mode 100644 "\351\222\237\351\270\243\346\235\260/20240606_EFCore\347\256\200\344\273\213.md" create mode 100644 "\351\222\237\351\270\243\346\235\260/20240607_EFCore\347\232\204\344\275\277\347\224\250.md" diff --git "a/\351\222\237\351\270\243\346\235\260/20240603_\351\241\271\347\233\256\345\256\236\347\216\260--\344\275\234\350\200\205Dto\345\206\231\346\263\225.md" "b/\351\222\237\351\270\243\346\235\260/20240603_\351\241\271\347\233\256\345\256\236\347\216\260--\344\275\234\350\200\205Dto\345\206\231\346\263\225.md" new file mode 100644 index 0000000..ffb9446 --- /dev/null +++ "b/\351\222\237\351\270\243\346\235\260/20240603_\351\241\271\347\233\256\345\256\236\347\216\260--\344\275\234\350\200\205Dto\345\206\231\346\263\225.md" @@ -0,0 +1,157 @@ +Dto的好处 +数据封装与传输:DTO用于在不同层之间传递数据,特别是在控制器和服务层之间。它能够将请求中的数据进行封装,从而便于传输。 +解耦:通过使用DTO,可以避免直接暴露数据库模型(这里指Domain中的文件),从而降低各层之间的耦合度。 +数据验证与格式化:DTO可以添加数据注释和验证属性,确保传入的数据符合预期格式和约束。这样可以在数据到达业务逻辑层之前进行初步验证。 +安全性:可以避免将敏感的数据库字段直接暴露给客户端。 +数据转换:以用于将复杂的数据结构转换为适合传输的简单结构,或者将客户端传入的数据转换为适合业务逻辑处理的结构。 +使用Dto的写法(记得引入Dto) +Interfaces接口 +public interface IAuthorRepository +{ + // 获取全部作者 + ICollection GetAllAuthors(); + // 获取指定id作者 + AuthorDto? GetAuthorById(Guid id); + // 添加作者 + AuthorDto AddAuthor(CreateAuthorDto createAuthorDto); + // 修改作者 + AuthorDto? UpdateAuthor(Guid id, UpdateAuthorDto updateAuthorDto); + // 删除作者 + string DelAuthor(Guid id); +} +Service实现接口——增删改查的操作都写在这里 +//-------------------获取全部作者------------------------------ + public ICollection GetAllAuthors() + { + // 用于存储转换为Dto类型后的作者信息 + var resList = new List(); + var list = BookStoreDb.Instance.Authors.ToList(); + list.ForEach(item => { + // 将数据转换为Dto对象,并添加到resList中 + /* 实例化一个对象有2种方式: + 1.直接调用构造函数,形如:new AuthorDto(......) + 2.直接填充其属性值,形如:new AuthorDto{......},像下面一样 + */ + resList.Add(new AuthorDto{ + Id = item.Id, + AuthorName = item.AuthorName, + Gender = item.Gender + }); + }); + return resList; + } +//-------------------获取指定id作者------------------------------ + public AuthorDto? GetAuthorById(Guid id) + { + var tmp = BookStoreDb.Instance.Authors.SingleOrDefault(item => item.Id == id); + /* + 如果匹配的结果tmp不为null,则则创建一个新的 AuthorDto 对象(tmpResult),并将 tmp 中的属性值赋给它 + 如果没有找到匹配的结果,则将tmpResult 设置为 null + */ + var tmpResult = tmp != null? new AuthorDto{ + Id = tmp.Id, + AuthorName = tmp.AuthorName, + Gender = tmp.Gender + }:null; + return tmpResult; + } +//-------------------添加作者------------------------------ + public AuthorDto AddAuthor(CreateAuthorDto createAuthorDto) + { + // 将传入的dto转换为保存到内存数据库需要的实体类型Authors + var author = new Authors{ + Id = Guid.NewGuid(), + AuthorName = createAuthorDto.AuthorName, + Gender = createAuthorDto.Gender, + Birthday = createAuthorDto.Birthday + }; + // 添加操作 + BookStoreDb.Instance.Authors.Add(author); + // 将内存数据库获取的数据转换为AuthorDto的实例,以Dto类型返回 + var authorDto = new AuthorDto{ + Id = author.Id, + AuthorName = author.AuthorName, + Gender = author.Gender, + }; + return authorDto; + } +//-------------------修改作者------------------------------ + public AuthorDto? UpdateAuthor(Guid id, UpdateAuthorDto updateAuthorDto) + { + // 查找指定id数据 + var item = BookStoreDb.Instance.Authors.SingleOrDefault(item => item.Id == id); + // 未找到就返回null + if(item == null){ + return null; + } + // 找到后就进行数据更新 + item.AuthorName = updateAuthorDto.AuthorName; + item.Gender = updateAuthorDto.Gender; + item.Birthday = updateAuthorDto.Birthday; + // 根据更新后的作者信息创建一个新的dto对象 + var res = new AuthorDto{ + Id = item.Id, + AuthorName = item.AuthorName, + Gender = item.Gender + }; + return res; + } +//-------------------删除作者------------------------------ + //这里尝试返回string类型,成功! + public string DelAuthor(Guid id) + { + var item = BookStoreDb.Instance.Authors.SingleOrDefault(item => item.Id == id); + if(item != null){ + var delAuthor = BookStoreDb.Instance.Authors.Remove(item); + return "删除成功"; + + }else{ + return "未找到删除对象"; + } + } +控制器——调用函数,尽量保持纯洁性 +// -----------------获取------------------------------------------ + [HttpGet("{id?}",Name = nameof(Get))] + public IActionResult Get(Guid id) + { + var noId = "00000000-0000-0000-0000-000000000000"; + if(id.ToString()==noId){ + var list = _authorRepsitory.GetAllAuthors(); + return Ok(list); + }else{ + var item = _authorRepsitory.GetAuthorById(id); + return Ok(item); + } + } +// -----------------添加------------------------------------------ + [HttpPost] + public IActionResult Post(CreateAuthorDto createAuthorDto) + { + /* 1.拿到CreateAuthorDto类型的实例化数据--模型绑定 + 2.将相关数据保存到数据库: + 1. 转换CreateAuthorDto类型的数据为Authors类型 + 2. 调用数据库上下文,将数据插入 + */ + var res = _authorRepsitory.AddAuthor(createAuthorDto); + if(res == null){ + return Ok("添加失败"); + } + return Ok("添加成功"); + } +// -----------------修改------------------------------------------ + [HttpPut("{id}")] + public IActionResult Put(Guid id,UpdateAuthorDto updateAuthorDto) + { + var res = _authorRepsitory.UpdateAuthor(id,updateAuthorDto); + if(res == null){ + return Ok("修改失败"); + } + return Ok("修改成功"); + } +// -----------------删除------------------------------------------ + [HttpDelete("{id}")] + public IActionResult Del(Guid id) + { + var res = _authorRepsitory.DelAuthor(id); + return Ok(res); + } \ No newline at end of file diff --git "a/\351\222\237\351\270\243\346\235\260/20240605_\351\241\271\347\233\256\345\256\236\347\216\260--\345\233\276\344\271\246\351\203\250\345\210\206.md" "b/\351\222\237\351\270\243\346\235\260/20240605_\351\241\271\347\233\256\345\256\236\347\216\260--\345\233\276\344\271\246\351\203\250\345\210\206.md" new file mode 100644 index 0000000..beedd4c --- /dev/null +++ "b/\351\222\237\351\270\243\346\235\260/20240605_\351\241\271\347\233\256\345\256\236\347\216\260--\345\233\276\344\271\246\351\203\250\345\210\206.md" @@ -0,0 +1,153 @@ +一、配置接口 +public interface IBookRepository +{ + // 获取指定id图书 + BookDto? GetBookById(Guid id); + // 获取全部图书 + ICollection GetAllBooks(Guid authorId); + // 添加图书 + BookDto AddBook(Guid authorId,AddBookDto addBookDto); + // 修改图书 + BookDto? UpdateBook(Guid bookId,BookDtoUpdate bookDtoUpdate); + // 删除图书 + string DelBook(Guid bookId); +} +二、实现接口 +// 添加图书 +public BookDto AddBook(Guid authorId,AddBookDto addBookDto) +{ + var book = new Books{ + Id = Guid.NewGuid(), + BooksName = addBookDto.BooksName, + Publiser = addBookDto.Publiser, + Price = addBookDto.Price, + AuthorId = authorId + }; + BookStoreDb.Instance.Books.Add(book); + var bookDto = new BookDto{ + Id = book.Id, + BooksName = book.BooksName, + Publiser = book.Publiser, + Price = book.Price, + AuthorId = book.AuthorId + }; + return bookDto; +} +// 获取全部图书 +public ICollection GetAllBooks(Guid authorId) +{ + var resList = new List(); + var list = BookStoreDb.Instance.Books.Where(b => b.AuthorId == authorId).ToList(); + list.ForEach(item => { + resList.Add(new BookDto{ + Id = item.Id, + BooksName = item.BooksName, + Publiser = item.Publiser, + Price = item.Price, + AuthorId = item.AuthorId + }); + }); + return resList; +} +// 获取指定id图书 +public BookDto? GetBookById(Guid id) +{ + var tmp = BookStoreDb.Instance.Books.SingleOrDefault(item=>item.Id==id); + var tmpResult = tmp != null? new BookDto{ + Id = tmp.Id, + BooksName = tmp.BooksName, + Publiser = tmp.Publiser, + Price = tmp.Price, + AuthorId = tmp.AuthorId + }:null; + return tmpResult; +} +// 修改图书 +public BookDto? UpdateBook(Guid bookId,BookDtoUpdate bookDtoUpdate) +{ + var item = BookStoreDb.Instance.Books.SingleOrDefault(b=>b.Id==bookId); + if(item == null){ + return null; + } + item.BooksName = bookDtoUpdate.BooksName; + item.Publiser = bookDtoUpdate.Publiser; + item.Price = bookDtoUpdate.Price; + var res = new BookDto{ + Id=item.Id, + Publiser=item.Publiser, + Price=item.Price + }; + return res; +} +// 删除图书 +public string DelBook(Guid id) +{ + var book = BookStoreDb.Instance.Books.SingleOrDefault(b => b.Id==id); + if(book != null){ + BookStoreDb.Instance.Books.Remove(book); + return "删除成功"; + } + return "删除失败"; +} +三、控制器操作 +//------------------------------获取图书----------------------------- + [HttpGet("{bookId?}")] + public IActionResult Get(Guid authorId,Guid? bookId) + { + var author = AuthorRepository.GetAuthorById(authorId); + if (author == null) + { + return NotFound("未找到作者"); + } + + if (bookId.HasValue) + { + var book = BookRepository.GetBookById(bookId.Value); + if (book == null || book.AuthorId != authorId) + { + return NotFound("未找到该图书"); + } + return Ok(book); + } + else + { + var books = BookRepository.GetAllBooks(authorId); + return Ok(books); + } + } +//------------------------------添加图书----------------------------- + [HttpPost] + public IActionResult Post(Guid authorId,AddBookDto addBookDto) + { + var author = AuthorRepository.GetAuthorById(authorId); + if(author == null){ + return NotFound("未找到作者"); + } + var bookDto = BookRepository.AddBook(authorId, addBookDto); + return Ok(bookDto); + } +//------------------------------修改图书----------------------------- + [HttpPut("{bookId}")] + public IActionResult Put(Guid authorId,Guid bookId,BookDtoUpdate bookDtoUpdate) + { + var author = AuthorRepository.GetAuthorById(authorId); + if(author == null){ + return NotFound("未找到作者"); + } + var res = BookRepository.UpdateBook(bookId,bookDtoUpdate); + if(res == null){ + return Ok("修改失败"); + } + return Ok("修改成功"); + } +//------------------------------删除图书----------------------------- + [HttpDelete("{bookId}")] + public IActionResult Del(Guid authorId,Guid bookId) + { + var author = AuthorRepository.GetAuthorById(authorId); + if(author == null){ + return NotFound("未找到作者"); + } + var book = BookRepository.DelBook(bookId); + return Ok(book); + } diff --git "a/\351\222\237\351\270\243\346\235\260/20240606_EFCore\347\256\200\344\273\213.md" "b/\351\222\237\351\270\243\346\235\260/20240606_EFCore\347\256\200\344\273\213.md" new file mode 100644 index 0000000..619a5bc --- /dev/null +++ "b/\351\222\237\351\270\243\346\235\260/20240606_EFCore\347\256\200\344\273\213.md" @@ -0,0 +1,33 @@ +一、EF Core的简介 +1.概念 +EF Core(Entity Framework Core)是基于.NET Core的轻量级ORM框架 +ORM能够处理数据库与高级编程语言中对象之间的映射关系 +2. .NET对象与关系型数据库的对应关系 +.NET对象 关系型数据库 +类 表 +类的属性或字段 表中的列 +集合中的元素 表中的行 +对于其他类的引用 外键 +3.支持LINQ(集成语言查询) +1.查询所有 +var result = from item in collection + select item; +2.过滤 +var result = from item in collection + where price > 10 + select item; +3.排序 +var result = from item in collection + orderby item.Property ascending/descending + select item; +//ascending(升序,默认);descending(降序)关键字 +4.连接查询 +var query = from person in people + join address in addresses on person.AddressId equals address.Id + select new { person.Name, address.City }; +二、在项目中添加EF Core +1.安装包 +dotnet add package Microsoft.EntityFrameworkCore +2.安装提供程序 +//这里为SQL Server数据库为例 +dotnet add package Microsoft.EntityFrameworkCore.SqlServer \ No newline at end of file diff --git "a/\351\222\237\351\270\243\346\235\260/20240607_EFCore\347\232\204\344\275\277\347\224\250.md" "b/\351\222\237\351\270\243\346\235\260/20240607_EFCore\347\232\204\344\275\277\347\224\250.md" new file mode 100644 index 0000000..8b3455c --- /dev/null +++ "b/\351\222\237\351\270\243\346\235\260/20240607_EFCore\347\232\204\344\275\277\347\224\250.md" @@ -0,0 +1,120 @@ +一、EF Core的两种使用方法 +1.代码优先(推荐) +根据先创建好的实体类来创建数据库和表 +EF Core会将对实体类的修改同步到数据库中,都是对数据库手工修改将会在EF Core同步数据后丢失 +用于同步代码到数据库的方法是迁移(Migration),就是提供以增量的方式来修改数据库和表结构,使实体类和数据库保持一致 +2.数据库优先 +根据先创建好的数据库生成相应的代码 + +二、EF Core的添加步骤(代码优先) +1.创建数据模型 +创建数据模型类,这些类将映射到数据库中的表 + +2. 配置数据库连接 +// appsetting.json +"ConnectionString":{ + Mssql:"server=.;database=BookStore;uid=sa;pwd=123456;TrustServerCertificate=true;" +} +3.配置数据库上下文DbContext +DbContext是非常重要的类,代表程序与数据库之间的会话或数据上下文,能够完成查询和保存数据等操作 +它的派生类中有若干个DbSet类型的公告属性,表示相应实体的集合,对它们的操作最后会反映到数据表 +// Db/BookStoreDbContext.cs +using Microsoft.EntityFrameworkCore; +namespace BookStore.Api.Db; +public class BookStoreDbContext:DbContext +{ + public DbSet Authors {get;set;} + public DbSet Books {get;set;} + // 构造函数接受一个 DbContextOptions 类型的参数 + // 将该参数传递给基类的构造函数 base(options) + // 这个构造函数用于配置数据库上下文的选项,例如数据库提供程序、连接字符串等 + public BookStoreDbContext(DbContextOptions options):base(options) + { + + } +} +注意点: + +提供正确的连接字符串 +必须构造函数选项配置 +4.注入服务,引入配置文件,实现连接数据库 +// Startup.cs +servuces.AddDbContext(config => + config.UseSqlServer(Configuration.GetConnectionString("Mssql")); + // 也可以直接在GetConnectionString()里写连接字符串内容 +) +注意: 这里UseSqlServer只有在Microsoft.EntityFrameworkcore.SqlServer包安装后才可以使用 + +5.生成迁移与创建数据库 +// 安装dotnet-ef工具 +dotnet tool install -g dotnet-ef +// 生成迁移 +dotnet ef migrations add <迁移名称> +// 如果迁移成功就会出现Migrations文件夹 + +// 创建数据库(同步) + +dotnet ef database update +// 创建成功就会在数据库出现表,其中会自带一个名为_EFMigrationsHistory的表,这是存储迁移的历史记录,删除就会导致程序运行失败 +注意: + +迁移名称最好是英文且首字母大写 +使用迁移前需要安装Microsoft.EntityFrameworkcore +需要全局安装dotnet-ef工具 +代码不能有错误,否则迁移中会报错 +6.添加种子数据 +方法一--为种子数据建模 +// OnModelCreating.cs +protected override void OnModelCreating(ModelBuilder modelBuider) +{ + base.OnModelCreating(modelBuider); + modelBuilder.Entity().HasData(new Author{ + Id = new Guid, + AuthorName = "小米" + }, + new Author{ + ...... + } + ); + modelBuilder.Entity().HasData(new Book{......}); +} +// HasData方法可添加一个或多个相同的实体类型 +注意: + +通常情况下数据库会自动生成主键值,但在种子数据中,您仍然需要为主键字段指定值 +如果以任何方式更改主键,将删除之前设定种子的数据 +方法二--手动迁移自定义 +解决 HasData 的某些限制的方法之一是改为手动向迁移添加这些调用或自定义操作 + +// 在Migrations目录下以_SeeData.cs结尾的文件中,包含两个方法Up和Down +//在Up方法中调用迁移生成器对象的InsertData方法 +migrationBuilder.InsertData( + table: "Authors", //目标表的名称 + columns: new[] { "Url" }, //目标表的名称 + values: new object[] { "http://generated.com" } //要插入列的值 +); +// 如果要给全部列插入数据,则直接省略columns 参数 +// 直接提供 values 参数中与表中列顺序相对应的数值 +方法三--自定义初始化逻辑 +在主应用程序逻辑开始执行之前使用 DbContext.SaveChanges()执行数据种子设定 + +//program.cs +public static void Main(string[] args) +{ + var app = CreateHostBuilder(args).Build(); + + // 在应用程序启动时执行数据种子逻辑 + using (var context = new DataSeedingContext()) + { + context.Database.EnsureCreated(); + // 检查是否存在该数据信息,若不存在则添加该数据 + var testBlog = context.Authors.FirstOrDefault(a => a.AuthorName == "小明"); + if (testBlog == null) + { + context.Authors.Add(new Author { AuthorName == "小明" }); + } + + context.SaveChanges(); + } + app.Run(); +} \ No newline at end of file -- Gitee