locked
Can EF be used for multiple projects? RRS feed

  • Question

  • I'm using EF6 and have a project which may need to be used for

    Internal web, internal forms.external web and possibly for mobile phone applications.

    I would like to use the correct/appropriate projects to get this structure to be correct where possible and for data access I would be using EF6 database first approach. There maybe a possibility that we need to use mySql or another database provider including unit tests.

    Can anyone advise what is the appropriate way to have the projects setup so it's loosely coupled? Should I have one project with EF6 installed adding all table Entities including my Interfaces?

    Is there a better approach? Any guides I could follow?

    Friday, July 10, 2020 6:23 AM

Answers

  • Hi Pure Deal,
    I think it is better to create a data access project (class library) that contains just your models and db context, then you can reference the dll file from bin folder to other project.
    Note: checking the MetaData Artifact Processing property in the Properties window, which is by default set to "Embed in Output Assembly".
    This property is very useful in scenarios where you want to use the use the model in different projects. Since the model is created as a class library project (.dll), all you need to do now is make a reference to the .dll in your project and supply the connection string. 
    More details you can refer to this thread and Michelle provide a link with a code example.
    Best Regards,
    Daniel Zhang


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Pure Deal Thursday, July 16, 2020 12:23 PM
    Monday, July 13, 2020 7:50 AM
  • Is there a sample project I could refer to and see which project would contain Entity Framework, or the interfaces which project would have the implementation? Just trying to get an idea of the best way to structure my application?

    https://github.com/darnold924/PublishingCompany

    I put the PublishingCompany layered ASP.NET Core MVC solution out on Github. Everything I have talked about has been architected into the solution.

    https://www.vbforums.com/showthread.php?540421-Tutorial-An-Introduction-to-the-ADO-NET-Entity-Framework

    The PubCompnay project is just a EF DB first project i have used over the years to learn new technology. It's a Windows form project tutorial using EF that I have converted over to c# and ASP.NET Core. The link actually works, and you just have to start scrolling down until you hit the tutorial beginning. 

    The key is the DTO pattern that is the classlib project Entities that is shared with all the other projects, which is an abstraction away from the underlying database technology. It means that all the other layers above the DAL only see the DTO(s). The whole DAL database technology could change from EF to nHibernate or MS SQL Server over to Oracle,  and the other layers would be unaffected, because all they ever see is the DTO(s).

    Also, I choose the DAO pattern, becuase EF is already using the UoW and Repository patterns and using the patterns in code is not optimal programming over EF, particularly the generic repository pattern.

    https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext?view=efcore-3.1

    https://programmingwithmosh.com/net/common-mistakes-with-the-repository-pattern/

    If you put the DAL with EF using an ASP.NET WebAPI, then any project type can do CRUD with the database using the WebAPI service.



    • Edited by DA924x Monday, July 13, 2020 5:03 PM
    • Marked as answer by Pure Deal Thursday, July 16, 2020 12:23 PM
    Monday, July 13, 2020 4:56 PM

All replies

  • You should be using SoC in the solution that promotes loose coupling using a Data Access Layer (DAL).

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

    You could look into the DAO and DTO patterns with DTO pattern used throughout the solutions.

    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

    You should look into layered or n-tier.

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ee658117(v=pandp.10)

    You could look into using ASP.NET WebAPI having DAL sitting behind the WebAPI doing CURD with the database using EF for various WebAPI client side software.

    Also, you may want to abandon EF 6 DB first approach for EF 6 code first for an existing database, since EF Core has abandoned the EDMX.

    https://docs.microsoft.com/en-us/ef/ef6/modeling/code-first/workflows/existing-database

    Example of WebAPI using DAO and DTO patterns

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using DAL;
    using Entities;
    using Microsoft.AspNetCore.Mvc;
    
    namespace WebApi3.x.Controllers
    {
        [Route("[controller]")]
        [ApiController]
        public class PayRollController : ControllerBase
        {
            private IDaoPayroll dao;
            public PayRollController(IDaoPayroll daoPayroll)
            {
                dao = daoPayroll;
            }
    
            [HttpGet]
            [Route("GetAll")]
            public async Task<List<DtoPayroll>> GetAll()
            {
                return await dao.GetAll();
            }
    
            [HttpGet]
            [Route("Find")]
            public async Task<DtoPayroll> Find(int id)
            {
                return await dao.Find(id);
            }
    
    
            [HttpGet]
            [Route("FindPayRollByAuthorId")]
            public async Task<DtoPayroll> FindPayRollByAuthorId(int id)
            {
                return await dao.FindPayRollByAuthorId(id);
            }
    
            [HttpPost]
            [Route("Add")]
            public async Task Add(DtoPayroll dto)
            {
                await dao.Add(dto);
            }
    
            [HttpPost]
            [Route("Update")]
            public async  Task Update(DtoPayroll dto)
            {
                 await dao.Update(dto);
            }
    
            [HttpPost]
            [Route("Delete")]
            public async Task Delete(DtoId dto)
            {
                await dao.Delete(dto.Id);
            }
        }
    }

    using Entities;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace DAL
    {
        public interface IDaoPayroll
        {
            Task<List<DtoPayroll>> GetAll();
            Task<DtoPayroll> Find(int id);
            Task<DtoPayroll> FindPayRollByAuthorId(int id);
            Task Add(DtoPayroll dto);
            Task Update(DtoPayroll dto);
            Task Delete(int id);
        }
    }
    ============================================================
    
    using DAL.Models;
    using System;
    using System.Threading.Tasks;
    using Entities;
    using System.Collections.Generic;
    using Microsoft.EntityFrameworkCore;
    using System.Data.SqlClient;
    using System.Linq;
    
    namespace DAL
    {
        public class DaoPayroll :IDaoPayroll
        {
            private PublishingCompanyContext pc;
            private IDaoAuthor _daoauthor;
    
            public DaoPayroll(PublishingCompanyContext dbcontext, IDaoAuthor daoAuthor)
            {
                pc = dbcontext;
                _daoauthor = daoAuthor;
            }
    
            public async Task<List<DtoPayroll>> GetAll()
            {
                var dtos = new List<DtoPayroll>();
    
                var payrolls = await pc.Payroll.ToListAsync();
    
                foreach (var payroll in payrolls)
                {
                    var dtoauthor = await _daoauthor.Find(payroll.AuthorId); 
    
                    var dto = new DtoPayroll
                    {
                        PayRollId = payroll.PayrollId,
                        AuthorId = payroll.AuthorId,
                        AuthorFirstName = dtoauthor.FirstName,
                        AuthorLastName = dtoauthor.LastName,
                        Salary = payroll.Salary
                    };
    
                    dtos.Add(dto);
                }
    
                return dtos;
            }
    
            public async Task<DtoPayroll> Find(int id)
            {
                var dto = new DtoPayroll();
    
                var payroll = await pc.Payroll.FindAsync(id);
    
                if (payroll != null)
                { 
                    var dtoauthor = await _daoauthor.Find(payroll.AuthorId);
    
                    if (dtoauthor != null)
                    {
                        dto.PayRollId = payroll.PayrollId;
                        dto.AuthorId = payroll.AuthorId;
                        dto.AuthorFirstName = dtoauthor.FirstName;
                        dto.AuthorLastName = dtoauthor.LastName;
                        dto.Salary = payroll.Salary;
                    }
                    else
                    {
                        throw new Exception($"Author with ID = {id} was not found.");
                    }
                }
                else
                {
                    throw new Exception($"Payroll with ID = {id} was not found.");
                }
    
                return dto;
    
            }
    
            public async Task<DtoPayroll> FindPayRollByAuthorId(int id)
            {
                var dto = new DtoPayroll();
                
                var payroll = await pc.Payroll.Where(a =>a.AuthorId == id).SingleOrDefaultAsync();
    
                if (payroll != null)
                {
                    dto.PayRollId = payroll.PayrollId;
                }
    
                return dto;
            }
    
            public async Task Add(DtoPayroll dto)
            {
                var payroll = new Payroll
                {
                    AuthorId = dto.AuthorId,
                    Salary = dto.Salary
                };
    
                pc.Payroll.Add(payroll);
                await pc.SaveChangesAsync();
    
            }
    
            public async Task Update(DtoPayroll dto)
            {
                var payroll = new Payroll
                {
                    PayrollId = dto.PayRollId,
                    AuthorId = dto.AuthorId,
                    Salary = dto.Salary
                };
    
                pc.Entry(payroll).State = EntityState.Modified;
                await pc.SaveChangesAsync();
    
            }
    
            public async Task Delete(int id)
            {
                var payroll =  pc.Payroll.Find(id);
    
                if (payroll != null)
                {
                    pc.Payroll.Remove(payroll);
                    await pc.SaveChangesAsync();
                }
            }
    
        }
    }
    

    namespace Entities
    {
        public class DtoPayroll
        {
            public int PayRollId { get; set; }
            public int AuthorId { get; set; }
            public string AuthorFirstName { get; set; }
            public string AuthorLastName { get; set; }
            public int? Salary { get; set; }
        }
    }
    

    Saturday, July 11, 2020 4:28 PM
  • Is there a sample project I could refer to and see which project would contain Entity Framework, or the interfaces which project would have the implementation? Just trying to get an idea of the best way to structure my application?
    Sunday, July 12, 2020 8:25 PM
  • Hi Pure Deal,
    I think it is better to create a data access project (class library) that contains just your models and db context, then you can reference the dll file from bin folder to other project.
    Note: checking the MetaData Artifact Processing property in the Properties window, which is by default set to "Embed in Output Assembly".
    This property is very useful in scenarios where you want to use the use the model in different projects. Since the model is created as a class library project (.dll), all you need to do now is make a reference to the .dll in your project and supply the connection string. 
    More details you can refer to this thread and Michelle provide a link with a code example.
    Best Regards,
    Daniel Zhang


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Pure Deal Thursday, July 16, 2020 12:23 PM
    Monday, July 13, 2020 7:50 AM
  • Is there a sample project I could refer to and see which project would contain Entity Framework, or the interfaces which project would have the implementation? Just trying to get an idea of the best way to structure my application?

    https://github.com/darnold924/PublishingCompany

    I put the PublishingCompany layered ASP.NET Core MVC solution out on Github. Everything I have talked about has been architected into the solution.

    https://www.vbforums.com/showthread.php?540421-Tutorial-An-Introduction-to-the-ADO-NET-Entity-Framework

    The PubCompnay project is just a EF DB first project i have used over the years to learn new technology. It's a Windows form project tutorial using EF that I have converted over to c# and ASP.NET Core. The link actually works, and you just have to start scrolling down until you hit the tutorial beginning. 

    The key is the DTO pattern that is the classlib project Entities that is shared with all the other projects, which is an abstraction away from the underlying database technology. It means that all the other layers above the DAL only see the DTO(s). The whole DAL database technology could change from EF to nHibernate or MS SQL Server over to Oracle,  and the other layers would be unaffected, because all they ever see is the DTO(s).

    Also, I choose the DAO pattern, becuase EF is already using the UoW and Repository patterns and using the patterns in code is not optimal programming over EF, particularly the generic repository pattern.

    https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext?view=efcore-3.1

    https://programmingwithmosh.com/net/common-mistakes-with-the-repository-pattern/

    If you put the DAL with EF using an ASP.NET WebAPI, then any project type can do CRUD with the database using the WebAPI service.



    • Edited by DA924x Monday, July 13, 2020 5:03 PM
    • Marked as answer by Pure Deal Thursday, July 16, 2020 12:23 PM
    Monday, July 13, 2020 4:56 PM
  • Thanks everyone I will check out the project and links posted and mark an answer.

    Coming from a DB first background I will try and change to code first if possible. To me it seems understanding Migrations is mainly the heavy lifting here. Are there any tools/add ons (preferably free) which I could utilise to shorten the learning curve or at least make this journey a bit more pain free? Including generating classes or converting my database to code first classes or similar


    • Edited by Pure Deal Tuesday, July 14, 2020 6:41 AM
    Tuesday, July 14, 2020 6:38 AM
  • Myself, I have never  used EF migrations. I don't  consider  any ORM to be a DBA tool.
    Tuesday, July 14, 2020 12:35 PM
  • Myself, I have never  used EF migrations. I don't  consider  any ORM to be a DBA tool.

    When I was reading up on EF what I came across was to update the database you have to create a migration then run that migration on the database for the update to become active.

    Are you suggesting you would do this manually as most of the threads I read forced many to use migrations (if I've understood this correctly) in order for the database to have any new columns/tables?

    Tuesday, July 14, 2020 8:44 PM
  • As long as the EF dbContext the program is using  that holds the persistence model matches the database schema, one can use traditional DBA tools for database migration and administration. One doesn't need to use EF migrations with it acting as some kind of DBA tool, which leads to a software developer using EF migrations as a crutch and not knowing basic DBA 101 skills any software developer should know when programming against a relational database such as MS SQL Server and others.
    Wednesday, July 15, 2020 5:35 AM