用VSCode開發一個基於asp.net core 2.0/sql server linux(docker)/ng5/bs4的專案(3)

solenovex發表於2018-03-09

第一部分: http://www.cnblogs.com/cgzl/p/8478993.html

第二部分: http://www.cnblogs.com/cgzl/p/8481825.html

由於本文主要是講VSCode開發等, 所以相關等一些angular/.net core的知識就相對少講點.

我把需求改一下, 如圖:

由於efcore目前還是使用中間表來建立多對多的關係, 所以分類標籤這個需求就沒什麼特別的了, 就去掉吧. 還有電視劇分季這個技術上也是重複的, 也刪掉.

目前只剩下電視臺和電視劇的維護, 還剩下的知識點是:

  • 集合的CRUD操作
  • 對專案結構進行整理, 使用Unit Of Work 以及 Repository 模式
  • 上傳檔案

由於CRUD畫面做起來比較簡單, 我相信大家使用該技術的都會, 所以我直接把我寫完的程式碼傳上來. 此時頁面的操作效果請看視訊:

這時的程式碼: 

https://pan.baidu.com/s/1egCmuNT0OxJNwkz0OQ72kA

這裡面又一個比較常見的問題, 就是

針對集合的增刪改:

上述業務的電視劇的增刪改就會出現這種情況:

資料庫裡面原來有4條資料, 而前臺操作完, 刪除了第3條資料, 並且增加了一條資料, 其餘資料的內容可能有變化.

這種集合類增刪改的思路應該是這樣的:

1.從傳進來的集合找出所有新新增的資料(新新增的資料Id通常並不存在, 這是條件), 放在一個臨時的集合, 然後新增到context.

2.從資料庫集合找出所有需要刪除的資料(有一些id在傳進來的集合找不到的就是), 放在一個集合, 然後從conetxt一次性移除.

3.兩個集合都有的資料就是隻需要修改內容的資料, 更新即可.

下面開始實現這個功能:

首先確保Put方法裡, 把電視臺下所有的電視劇都讀取出來:

 

接下來, 找到MappingProfile.cs, 使用AutoMapper來實現這個功能.

首先要忽略預設的集合對映:

然後呼叫AfterMap方法做後期手動處理, 程式碼的意思大概是這樣:

或者, 也可以用Linq做一些重構:

回到畫面試一下編輯功能:

然後新增和刪除:

檢視結果:

OK.

 

專案重構

下面, 我們使用Unit Of Work以及Repository Pattern對專案進行重構:

由於這部分也很簡單, 並且也不是這篇文章的重點, 我就直接貼出重構後的程式碼吧:

Database/TvRepostiory.cs:

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Tv.Models;

namespace Tv.Database
{
    public class TvRepository : ITvRepostitory
    {
        private readonly TvContext context;

        public TvRepository(TvContext context)
        {
            this.context = context;
        }

        public async Task<List<TvNetwork>> GetTvNetworksAsync()
        {
            return await context.TvNetworks.Include(x => x.TvShows).ToListAsync();
        }

        public async Task<TvNetwork> GetTvNetworkByIdAsync(int id, bool includeRelated = true)
        {
            if (includeRelated)
            {
                return await context.TvNetworks.Include(x => x.TvShows).SingleOrDefaultAsync(x => x.Id == id);
            }
            return await context.TvNetworks.FindAsync(id);
        }

        public void AddTvNetwork(TvNetwork model)
        {
            context.TvNetworks.Add(model);
        }

        public void RemoveTvNetwork(TvNetwork model)
        {
            context.TvNetworks.Remove(model);
        }
    }
}

Database/ITvRepository.cs:

using System.Collections.Generic;
using System.Threading.Tasks;
using Tv.Models;

namespace Tv.Database
{
    public interface ITvRepostitory
    {
        Task<List<TvNetwork>> GetTvNetworksAsync();
        Task<TvNetwork> GetTvNetworkByIdAsync(int id, bool includeRelated = true);
        void AddTvNetwork(TvNetwork model);
        void RemoveTvNetwork(TvNetwork model);
    }
}

Database/UnitOfWork.cs:

using System.Threading.Tasks;

namespace Tv.Database
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly TvContext context;

        public UnitOfWork(TvContext context)
        {
            this.context = context;
        }

        public async Task SaveAsync()
        {
            await context.SaveChangesAsync();
        }
    }
}

Database/IUnitOfWork.cs:

using System.Threading.Tasks;

namespace Tv.Database
{
    public interface IUnitOfWork
    {
        Task SaveAsync();
    }
}

Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddAutoMapper();
            // services.AddDbContext<TvContext>(opt => opt.UseSqlServer(Configuration["ConnectionStrings:Default"]));
            services.AddDbContext<TvContext>(opt => opt.UseSqlServer(Configuration.GetConnectionString("Default")));
            services.AddScoped<ITvRepostitory, TvRepository>();
            services.AddScoped<IUnitOfWork, UnitOfWork>();
            services.AddMvc();
        }

TvController.cs:

using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Tv.Database;
using Tv.Models;
using Tv.ViewModels;

namespace Tv.Controllers
{
    public class TvController : Controller
    {
        private readonly ITvRepostitory repostiory;
        private readonly IUnitOfWork unitOfWork;
        private readonly IMapper mapper;

        public TvController(ITvRepostitory repostiory, IUnitOfWork unitOfWork, IMapper mapper)
        {
            this.repostiory = repostiory;
            this.unitOfWork = unitOfWork;
            this.mapper = mapper;
        }

        [HttpGet("api/tvnetworks")]
        public async Task<IEnumerable<TvNetworkViewModel>> GetTvNetworks()
        {
            var models = await repostiory.GetTvNetworksAsync();
            var vms = mapper.Map<List<TvNetwork>, List<TvNetworkViewModel>>(models);
            return vms;
        }

        [HttpGet("api/tvnetworks/{id}")]
        public async Task<IActionResult> Get(int id)
        {
            var model = await repostiory.GetTvNetworkByIdAsync(id);
            var vm = mapper.Map<TvNetwork, TvNetworkViewModel>(model);
            return Ok(vm);
        }

        [HttpPost("api/tvnetworks")]
        public async Task<IActionResult> Post([FromBody]TvNetworkUpdateViewModel vm)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var model = mapper.Map<TvNetworkUpdateViewModel, TvNetwork>(vm);
            repostiory.AddTvNetwork(model);
            await unitOfWork.SaveAsync();
            var result = mapper.Map<TvNetwork, TvNetworkViewModel>(model);
            return Ok(result);
        }

        [HttpPut("api/tvnetworks/{id}")]
        public async Task<IActionResult> Put(int id, [FromBody]TvNetworkUpdateViewModel vm)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var dbModel = await repostiory.GetTvNetworkByIdAsync(id);
            if (dbModel == null)
            {
                return NotFound();
            }
            var model = mapper.Map<TvNetworkUpdateViewModel, TvNetwork>(vm, dbModel);
            await unitOfWork.SaveAsync();
            var result = mapper.Map<TvNetwork, TvNetworkViewModel>(model);
            return Ok(result);
        }

        [HttpDelete("api/tvnetworks/{id}")]
        public async Task<IActionResult> Delete(int id)
        {
            var model = await repostiory.GetTvNetworkByIdAsync(id, includeRelated: false);
            if (model == null)
            {
                return NotFound();
            }
            repostiory.RemoveTvNetwork(model);
            await unitOfWork.SaveAsync();
            return NoContent();
        }
    }
}

 

再操作下畫面, 沒有任何問題.

 

 

今天先寫到這, VSCode的開發速度還是非常快的.

還剩下最後一部分--上傳檔案.

相關文章