好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

MongoDB入门实战教程(5)

‘ Books ‘ )

最后,预先插入两条测试数据:

 db.Books.insertMany([
{  ‘  Name  ‘ : ‘  Design Patterns  ‘ , ‘  Price  ‘ : 54.93  ,
  ‘  Category  ‘ : ‘  Computers  ‘ , ‘  Author  ‘ : ‘  Ralph Johnson  ‘  , 
  ‘  CreatedDate  ‘ :ISODate( "  2012-10-02T07:58:51Z  "  ),
  ‘  UpdatedDate  ‘ :ISODate( "  2012-10-02T07:58:51Z  "  )}, 
{  ‘  Name  ‘ : ‘  Clean Code  ‘ , ‘  Price  ‘ : 43.15  ,
  ‘  Category  ‘ : ‘  Computers  ‘ , ‘  Author  ‘ : ‘  Robert C. Martin  ‘  ,
  ‘  CreatedDate  ‘ :ISODate( "  2012-10-02T07:58:51Z  "  ),
  ‘  UpdatedDate  ‘ :ISODate( "  2012-10-02T07:58:51Z  " )}])

2 配置ASP.NET Core项目

创建WebAPI项目

建立一个ASP.NET Core 或 ASP.NET 5的WebAPI项目。

通过NuGet安装MongoDB.Driver:

PM>Install-Package MongoDB.Driver

目前MongoDB.Driver最新版本为2.12.4(2021年6月5日发布)。一般来说,我们操作MongoDB都会选择这个官方的Driver。

添加实体模型

在WebAPI项目中添加Models目录,并增加 Book 实体类:

 public   class   Book : MongoDocBase
{
    [BsonElement(  "  Name  "  )]
      public   string  BookName {  get ;  set  ; }

      public   decimal  Price {  get ;  set  ; }

      public   string  Category {  get ;  set  ; }

      public   string  Author {  get ;  set  ; }
}

  public   class   MongoDocBase
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
      public   string  Id {  get ;  set  ; }

    [BsonDateTimeOptions(Kind  =  DateTimeKind.Local)]
      public  DateTime? CreatedDate {  get ;  set  ; }

    [BsonDateTimeOptions(Kind  =  DateTimeKind.Local)]
      public  DateTime? UpdatedDate {  get ;  set  ; }
} 

需要注意的是:MongoDB存储时间类型数据时,都是先转换为UTC时间,然后存储到数据库中。当我们取出存储的时间时,就会出现时差的问题。因此,一般我们会给文档中的日期类型加上如下所示的注解,将它转换为本地时间传输:

[BsonDateTimeOptions(Kind = DateTimeKind.Local)]

在实际应用中,我们会给实体类创建一些DTO,然后在应用层进行DTO向DO的转换。因此,这里我们假设会进行 创建Book 和 修改Book 的操作,创建两个DTO类:

(1)CreateBookDto

 public   class   CreateBookDto
{
      public   string  BookName {  get ;  set  ; }

      public   decimal  Price {  get ;  set  ; }

      public   string  Category {  get ;  set  ; }

      public   string  Author {  get ;  set  ; }

    [JsonIgnore]
      public  DateTime CreatedDate {  get ;  set ; } =  DateTime.Now;
} 

(2)UpdateBookDto

 public   class   UpdateBookDto : CreateBookDto
{
      public   string  Id {  get ;  set  ; }

    [JsonIgnore]
      public  DateTime UpdatedDate {  get ;  set ; } =  DateTime.Now;
} 

在本示例中,使用AutoMapper进行DTO和DO之间的互转,因此,安装 AutoMapper 及其 扩展:

PM>Install- Package AutoMapper
PM >Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

创建映射规则配置:

 public   class   MappingConfigs : Profile
{
      public   MappingConfigs()
    {
        CreateMap <CreateBookDto, Book> ().ReverseMap();
        CreateMap <UpdateBookDto, Book> ()
            .ForMember(dest  => dest.CreatedDate, opt =>  opt.Ignore())
            .ReverseMap();
    }
} 

添加配置模型

首先,在appSettings.json中添加以下数据库配置:

 {
  ......
    "  BookstoreDatabaseSettings  "  : {
      "  BooksCollectionName  " :  "  Books  "  ,
      "  ConnectionString  " :  "  mongodb://mongo-master:27017  "  ,
      "  DatabaseName  " :  "  BookStoreDB  "  
  }
} 

需要注意的是:这里的连接字符串指向的是一个没有设置用户名密码的MongoDB节点。如果你的MongoDB节点设置了用户名密码 或者 复制集分片集 之类的,请修改为匹配的连接字符串。

然后,创建一个配置项类,也放到Models目录中:

 namespace   EDT.BookStore.API.Models
{
      public   class   BookStoreDatabaseSettings : IBookStoreDatabaseSettings
    {
          public   string  BooksCollectionName {  get ;  set  ; }
          public   string  ConnectionString {  get ;  set  ; }
          public   string  DatabaseName {  get ;  set  ; }
    }

      public   interface   IBookStoreDatabaseSettings
    {
          string  BooksCollectionName {  get ;  set  ; }
          string  ConnectionString {  get ;  set  ; }
          string  DatabaseName {  get ;  set  ; }
    }
} 

最后,将其加入到IoC容器中控制:

 public   void   ConfigureServices(IServiceCollection services)
{
    .....
    
      //   AutoMapper Settings 
    services.AddAutoMapper( typeof  (MappingConfigs));

      //   MongoDB Settings 
    services.Configure<BookStoreDatabaseSettings> (
        Configuration.GetSection(nameof(BookStoreDatabaseSettings)));
    services.AddSingleton <IBookStoreDatabaseSettings>(sp => 
        sp.GetRequiredService <IOptions<BookStoreDatabaseSettings>> ().Value);
} 

这里,IBookstoreDatabaseSettings 接口使用单一实例服务生存期在 DI 中注册。在注入时,接口实例时将解析为 BookStoreDatabaseSettings 对象。

添加BookService提供CRUD服务

在Services目录下,创建IBookService接口:

 namespace   EDT.BookStore.API.Services
{
      public   interface   IBookService
    {
        IList <Book>  Get();

        Task <IList<Book>>  GetAsync();

        Book Get(  string   id);

        Task <Book> GetAsync( string   id);

        Book Create(Book book);

        Task <Book>  CreateAsync(Book book);

          void  Update( string   id, Book bookIn);

        Task UpdateAsync(  string   id, Book bookIn);

          void  Remove( string   id);

        Task RemoveAsync(  string   id);
    }
} 

然后,创建BookService 实现 IBookService 接口。

 namespace   EDT.BookStore.API.Services
{
      public   class   BookService : IBookService
    {
          private   readonly  IMongoCollection<Book>  _books;

          public   BookService(IBookStoreDatabaseSettings settings)
        {
              var  mongoClient =  new   MongoClient(settings.ConnectionString);
              var  mongoDatabase =  mongoClient.GetDatabase(settings.DatabaseName);
            _books  = mongoDatabase.GetCollection<Book> (settings.BooksCollectionName);
        }

          public   Book Create(Book book)
        {
            _books.InsertOne(book);
              return   book;
        }

          public   async  Task<Book>  CreateAsync(Book book)
        {
              await   _books.InsertOneAsync(book);
              return   book;
        }

          public  IList<Book>  Get()
        {
              return  _books.Find(book =>  true  ).ToList();
        }

          public   async  Task<IList<Book>>  GetAsync()
        {
              return   await  _books.Find(book =>  true  ).ToListAsync();
        }

          public  Book Get( string   id)
        {
              return  _books.Find(book => book.Id ==  id).FirstOrDefault();
        }

          public   async  Task<Book> GetAsync( string   id)
        {
              return   await  _books.Find(book => book.Id ==  id).FirstOrDefaultAsync();
        }

          public   void  Remove( string   id)
        {
            _books.DeleteOne(book  => book.Id ==  id);
        }

          public   async  Task RemoveAsync( string   id)
        {
              await  _books.DeleteOneAsync(book => book.Id ==  id);
        }

          public   void  Update( string   id, Book bookIn)
        {
            _books.ReplaceOne(book  => book.Id ==  id, bookIn);
        }

          public   async  Task UpdateAsync( string   id, Book bookIn)
        {
              await  _books.ReplaceOneAsync(book => book.Id ==  id, bookIn);
        }
    }
} 

在上面的代码中,会通过构造函数从DI检索IBookStoreDatabaseSettings实例获取MongoDB连接字符串、数据库名 和 集合名。

当然,我们也可以使用 约定大于配置 的方式,统一采用实体类的名字 作为默认的 集合名,示例如下:

_books = mongoDatabase.GetCollection<Book>( typeof (Book).Name);

最后,将BookService也加入到IoC容器中:

services.AddSingleton<IBookService, BookService>();

这里,将BookService作为单一实例注入,这是因为 BookService 直接依赖于 MongoClient,而根据官方Mongo Client重用准则,我们应该使用单一实例服务在IoC容器中注入MongoClient。

添加Controller提供应用层接口

在Controllers目录下,新增 BookController 控制器:

 namespace   EDT.BookStore.API.Controllers
{
    [ApiController]
    [Route(  "  [controller]  "  )]
      public   class   BookController : ControllerBase
    {
          private   readonly   IMapper _mapper;
          private   readonly   IBookService _bookService;

          public   BookController(IMapper mapper, IBookService bookService)
        {
            _mapper  =  mapper;
            _bookService  =  bookService;
        }

        [HttpGet]
        [ProducesResponseType(  typeof (IList<Book> ), StatusCodes.Status200OK)]
        [ProducesResponseType(  typeof (IList<Book> ), StatusCodes.Status204NoContent)]
          public   async  Task<ActionResult<IList<Book>>>  Get()
        {
              var  books =  await   _bookService.GetAsync();
              if  (books ==  null  )
            {
                  return   NoContent();
            }

              return   Ok(books);
        }

        [HttpGet(  "  {id:length(24)}  " , Name =  "  GetBook  "  )]
        [ProducesResponseType(  typeof  (Book), StatusCodes.Status200OK)]
        [ProducesResponseType(  typeof  (Book), StatusCodes.Status404NotFound)]
          public   async  Task<ActionResult<Book>> Get( string   id)
        {
              var  book =  await   _bookService.GetAsync(id);
              if  (book ==  null  )
            {
                  return   NotFound();
            }

              return   Ok(book);
        }

        [HttpPost]
        [ProducesResponseType(  typeof  (Book), StatusCodes.Status201Created)]
          public   async  Task<ActionResult<Book>>  Create(CreateBookDto bookDto)
        {
              var  book = _mapper.Map<Book> (bookDto);
              await   _bookService.CreateAsync(book);
              return  CreatedAtRoute( "  GetBook  " ,  new  { id =  book.Id.ToString() }, bookDto);
        }

        [HttpPut(  "  {id:length(24)}  "  )]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
          public   async  Task<ActionResult> Update( string   id, UpdateBookDto bookDto)
        {
              var  book =  await   _bookService.GetAsync(id);
              if  (book ==  null  )
            {
                  return   NotFound();
            }

            _mapper.Map(bookDto, book);

              await   _bookService.UpdateAsync(id, book);
              return   Ok();
        }

        [HttpDelete(  "  {id:length(24)}  "  )]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
          public   async  Task<ActionResult> Update( string   id)
        {
              var  book =  await   _bookService.GetAsync(id);
              if  (book ==  null  )
            {
                  return   NotFound();
            }

              await   _bookService.RemoveAsync(id);
              return   Ok();
        }
    }
} 

3 测试ASP.NET Core WebAPI

生成该ASP.NET Core WebAPI应用,启动之后在Swagger页面进行测试:

点击GET /Book接口,测试结果如下:

其他接口测试结果不再赘述,有兴趣的童鞋可以自行跑起来测试一下。

示例github地址:https://github.com/EdisonChou/EDT.Mongo.Sample

4 总结

本文总结了如何在ASP.NET Core/ASP.NET 5应用程序中操作MongoDB,展示了一个麻雀虽小但五脏俱全的示例,希望能对你有所帮助。

参考资料

Microsoft Doc,使用ASP.NET Core和MongoDB创建WebAPI

唐建法,《MongoDB高手课》(极客时间)

郭远威,《MongoDB实战指南》(图书)

△推荐订阅学习

 

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

MongoDB入门实战教程(5)

标签:git   load   var   rev   直接   控制器   netcore   etc   drive   

查看更多关于MongoDB入门实战教程(5)的详细内容...

  阅读:27次