locked
Async with Data Access Classes RRS feed

  • Question

  • User1122355199 posted

    Hello everyone and thanks for the help in advance.  I have a Core 3.1 web application using EF Core for DB access.  I want to create an insert class that receives a set of parameters that in turn inserts the record.  This might be called by multiple points in the application, so I want to place this in a separate accessible class.  However, I am confused on exactly how to do this especially with async and await.  Would someone be able to point me to an example?

    Sunday, June 21, 2020 1:41 AM

Answers

  • User-821857111 posted

    Await doesn't block anything - quite the reverse: https://www.pluralsight.com/guides/understand-control-flow-async-await

    You need to ensure that all calls in the chain, starting with your action, are async too, otherwise the operation will be synchronous:

    public async Task<IActionResult> Method()
    {
        var data = await _myService.DoSomething();
        return View(data);
    }

    public async Task<List<Data>> DoSomething()
    {
        return await context.Things.ToListAsync();
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, June 26, 2020 4:21 AM
  • User1120430333 posted

    kmcnet

    Thanks for the response.  The articles and examples were very helpful.  However, I am still confused on how to implement this with a web application that calls a potentially long running process.  I understand the idea of an async task, but calling the task seems to require an await operator which, if I understand correctly, blocks further processing.  Isn't this a problem?

    No you have a misconception about the await. 

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await

    <copied>

    The await operator doesn't block the thread that evaluates the async method.

    <end>

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using DAL;
    using Entities;
    using Microsoft.AspNetCore.Mvc;
    
    namespace WebApi3.x.Controllers
    {
        [Produces("application/json")]
        [Route("[controller]")]
        [ApiController]
        public class ArticleController : ControllerBase
        {
            private IDaoArticle dao;
            public ArticleController(IDaoArticle daoArticle)
            {
                dao = daoArticle;
            }
    
            [HttpGet]
            [Route("GetAll")]
            public async Task<List<DtoArticle>> GetAll()
            {
                return await dao.GetAll();
            }
    
            [HttpGet]
            [Route("GetArticlesByAuthorId")]
            public async Task<List<DtoArticle>> GetArticlesByAuthorId(int id)
            {
                return await dao.GetArticlesByAuthorId(id);
            }
    
    
            [HttpGet]
            [Route("Find")]
            public async Task<DtoArticle> Find(int id)
            {
                return await dao.Find(id);
            }
    
            [HttpPost]
            [Route("Add")]
            public async Task Add(DtoArticle dto)
            {
                await dao.Add(dto);
            }
    
            [HttpPost]
            [Route("Update")]
            public async Task Update(DtoArticle dto)
            {
                await dao.Update(dto);
            }
    
            [HttpPost]
            [Route("Delete")]
            public async Task Delete(DtoId dto)
            {
                await dao.Delete(dto.Id);
            }
        }
    }



    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, June 26, 2020 4:40 AM

All replies

  • User1120430333 posted

    Hello everyone and thanks for the help in advance.  I have a Core 3.1 web application using EF Core for DB access.  I want to create an insert class that receives a set of parameters that in turn inserts the record.  This might be called by multiple points in the application, so I want to place this in a separate accessible class.  However, I am confused on exactly how to do this especially with async and await.  Would someone be able to point me to an example?

    https://en.wikipedia.org/wiki/Separation_of_concerns

    https://javarevisited.blogspot.com/2013/01/data-access-object-dao-design-pattern-java-tutorial-example.html

    https://www.codeproject.com/articles/1050468/data-transfer-object-design-pattern-in-csharp

    Data Access Layer DAL using DAO and DTO patterns 

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Entities;
    
    namespace DAL
    {
        public interface IDaoArticle
        {
            Task<List<DtoArticle>> GetAll();
            Task<List<DtoArticle>> GetArticlesByAuthorId(int id);
            Task<DtoArticle> Find(int id);
            Task Add(DtoArticle dto);
            Task Update(DtoArticle dto);
            Task Delete(int id);
        }
    }
    =====================================================================
    using System;
    using System.Collections.Generic;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using DAL.Models;
    using Entities;
    using Microsoft.EntityFrameworkCore;
    
    namespace DAL
    {
        public class DaoArticle :IDaoArticle
        {
            private PublishingCompanyContext pc;
            private IDaoAuthor _daoAuthor;
    
            public DaoArticle(PublishingCompanyContext dbcontext, IDaoAuthor daoAuthor)
            { 
                pc = dbcontext;
                _daoAuthor = daoAuthor;
            }
            public async Task<List<DtoArticle>> GetAll()
            {
                var dtos = new List<DtoArticle>();
    
                var articles = await pc.Article.ToListAsync();
    
                dtos.AddRange(articles.Select(article => new DtoArticle()
                {
                    ArticleId = article.ArticleId,
                    AuthorId = article.AuthorId,
                    Title = article.Title,
                    Body = article.Body
                }).ToList());
    
                return dtos;
            }
    
            public async Task<List<DtoArticle>> GetArticlesByAuthorId(int id)
            {
                var dtos = new List<DtoArticle>();
    
                var articles = await pc.Article.Where(a => a.AuthorId.ToString().Contains(id.ToString())).ToListAsync();
               
                foreach (var article in articles)
                {
                    var intid = (int)article.AuthorId;
    
                    var dtoauthor = await _daoAuthor.Find(intid);
    
                    var dto = new DtoArticle
                    {
                        ArticleId = article.ArticleId,
                        AuthorId = article.AuthorId,
                        AuthorName = dtoauthor.LastName +", " + dtoauthor.FirstName,
                        Title = article.Title,
                        Body = article.Body
                    };
    
                    dtos.Add(dto);
                }
                 
                return dtos;
            }
            public async Task<DtoArticle> Find(int id)
            {
                var dto = new DtoArticle();
    
                var article = await pc.Article.FindAsync(id);
                
                if (article != null)
                {
                    dto.ArticleId = article.ArticleId;
                    dto.AuthorId = article.AuthorId;
                    dto.Title = article.Title;
                    dto.Body = article.Body;
                }
                else
                {
                    throw new Exception($"Article with ID = {id} was not found.");
                }
    
                return dto;
    
            }
    
            public async Task Add(DtoArticle dto)
            {
                var article = new Models.Article
                {
                    AuthorId = dto.AuthorId,
                    Title = dto.Title,
                    Body = dto.Body
                };
    
                pc.Article.Add(article);
                await pc.SaveChangesAsync();
    
            }
    
            public async Task Update(DtoArticle dto)
            {
                var article = new Article
                {
                    ArticleId = dto.ArticleId,
                    AuthorId = dto.AuthorId,
                    Title = dto.Title,
                    Body = dto.Body
                };
    
                pc.Entry(article).State = EntityState.Modified;
                await pc.SaveChangesAsync();
    
            }
    
            public async Task Delete(int id)
            {
                var article = pc.Article.Find(id);
    
                if (article != null)
                {
                    pc.Article.Remove(article);
                    await pc.SaveChangesAsync();
                }
            }
    
        }
    }
    
    
    using System;
    
    namespace Entities
    {
        public class DtoArticle
        {
            public int ArticleId { get; set; }
            public string Title { get; set; }
            public string Body { get; set; }
            public int AuthorId { get; set; }
            public string AuthorName { get; set; }
        }
    }
    

    Sunday, June 21, 2020 5:22 AM
  • User1122355199 posted

    Thanks for the response.  The articles and examples were very helpful.  However, I am still confused on how to implement this with a web application that calls a potentially long running process.  I understand the idea of an async task, but calling the task seems to require an await operator which, if I understand correctly, blocks further processing.  Isn't this a problem?

    Friday, June 26, 2020 1:51 AM
  • User-821857111 posted

    Await doesn't block anything - quite the reverse: https://www.pluralsight.com/guides/understand-control-flow-async-await

    You need to ensure that all calls in the chain, starting with your action, are async too, otherwise the operation will be synchronous:

    public async Task<IActionResult> Method()
    {
        var data = await _myService.DoSomething();
        return View(data);
    }

    public async Task<List<Data>> DoSomething()
    {
        return await context.Things.ToListAsync();
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, June 26, 2020 4:21 AM
  • User1120430333 posted

    kmcnet

    Thanks for the response.  The articles and examples were very helpful.  However, I am still confused on how to implement this with a web application that calls a potentially long running process.  I understand the idea of an async task, but calling the task seems to require an await operator which, if I understand correctly, blocks further processing.  Isn't this a problem?

    No you have a misconception about the await. 

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await

    <copied>

    The await operator doesn't block the thread that evaluates the async method.

    <end>

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using DAL;
    using Entities;
    using Microsoft.AspNetCore.Mvc;
    
    namespace WebApi3.x.Controllers
    {
        [Produces("application/json")]
        [Route("[controller]")]
        [ApiController]
        public class ArticleController : ControllerBase
        {
            private IDaoArticle dao;
            public ArticleController(IDaoArticle daoArticle)
            {
                dao = daoArticle;
            }
    
            [HttpGet]
            [Route("GetAll")]
            public async Task<List<DtoArticle>> GetAll()
            {
                return await dao.GetAll();
            }
    
            [HttpGet]
            [Route("GetArticlesByAuthorId")]
            public async Task<List<DtoArticle>> GetArticlesByAuthorId(int id)
            {
                return await dao.GetArticlesByAuthorId(id);
            }
    
    
            [HttpGet]
            [Route("Find")]
            public async Task<DtoArticle> Find(int id)
            {
                return await dao.Find(id);
            }
    
            [HttpPost]
            [Route("Add")]
            public async Task Add(DtoArticle dto)
            {
                await dao.Add(dto);
            }
    
            [HttpPost]
            [Route("Update")]
            public async Task Update(DtoArticle dto)
            {
                await dao.Update(dto);
            }
    
            [HttpPost]
            [Route("Delete")]
            public async Task Delete(DtoId dto)
            {
                await dao.Delete(dto.Id);
            }
        }
    }



    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, June 26, 2020 4:40 AM
  • User1122355199 posted

    Perfect.  Thanks for the help.

    Tuesday, June 30, 2020 3:25 PM