ASP.NET MVC、EntityFramework、DBContext和Repository在不同项目中的应用

12
我目前正在开发一个ASP.NET MVC 5项目,试图优化该项目的架构;使其尽可能清晰易懂,方便未来的开发人员使用。首先,我将我的EntityFramework模型(包括IdentityUser和AccountViewModel)移动到同一解决方案中的类库项目中。目前,主MVC项目引用此项目。然而,我现在正在考虑创建一个新的数据访问层项目,其中将包含DbContext(或如果我决定使用多个DbContext,则为多个DbContext)以及数据访问层。如何最好地完成这项工作?这个DAL项目将引用Model项目,而主MVC项目将仅引用DAL项目。阅读了这篇文章后,我想知道当使用EntityFramework时,存储库模式是否已过时。因此,我的两个主要问题是:1)将DAL分离成单独的项目的最佳方法是什么?2)使用EF访问数据库内容的最佳方法是什么?

1
领域模型不等于视图模型。因此,“AccountViewModel”不应该是实体模型,或者至少不应该使用这个名称。 - Aage
确实!我刚才说过,我已经将MVC项目中的所有内容从Model文件夹移动到Model项目中(ASp.NET MVC默认将AccountViewModel放在Model文件夹中)。我计划将领域模型移动到另一个项目中。如果有任何建议,我很乐意听取! - teh0wner
要使用外部存储库,您应该将该存储库的引用添加到项目托管中!然后您需要使用 using YourProject.Models 等。附注:YourProject 应该(大多数情况下)是一个类库项目! - Bellash
1个回答

8
你的问题比较广泛。例如,“使用EF访问数据库内容的最佳方式”是什么意思?从性能方面来说最好的方式?
我会尝试通过给出我喜欢的选项(我大多数情况下都使用某种变体),来回答这个问题,它使用了存储库模式。如果您直接使用EF集作为存储库,您可能会认为您不需要存储库模式,但我喜欢将它们包装在自己的存储库中。
由于我无法知道您所说的最佳方式是什么,我将提供适合典型Web项目的个人偏好。
我不会发布所有代码以使其完全功能化,但您应该清楚正在发生什么。
设置(4个项目):
UI ----------> Domain.Logic(w.Domain.Models)-----------------> Data(持有EF上下文)。
数据:
public partial class EFContextContainer : DbContext 
enter code here
public EFContextContainer ()
        : base("name=EFContextContainer")
    {
    }

public DbSet<IdentityUser> IdentityUsers { get;set; } 

使用返回上下文的包装器:
public static class Database
{
    public static EFContextContainerGetContext()
    {
        return new EFContextContainer();
    }

}

你可以设置一个像这样的代码库:
接口:
public interface IRepository<T> where T : class
{
    IQueryable<T> GetAll();
    T GetById(Guid id);
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(Guid id);
}

实现(出于简洁起见,仅实现了Add(T entity)):

public class EFRepository<T> : IRepository<T>, IDisposable where T : class
{
    public EFRepository(DbContext dbContext)
    {
        if (dbContext == null)
            throw new ArgumentNullException("dbContext");
        DbContext = dbContext;
        DbSet = DbContext.Set<T>();

    }

    protected DbContext DbContext { get; set; }

    protected DbSet<T> DbSet { get; set; }

    public virtual void Add(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State != EntityState.Detached)
        {
            dbEntityEntry.State = EntityState.Added;
        }
        else
        {
            DbSet.Add(entity);
        }
    }

public void Dispose()
    {
        DbContext.Dispose();
    }

}

领域:

领域逻辑(IdentityUserManager将是Domain.Models中的一个类):

public class IdentityUserManager
{
    public void Add(IdentityUser idUser)
    {
        using(var idUserRepository = new EFRepository<IdentityUser>(Database.GetContext())
        {
            idUserRepository.Add(idUser);
        }
    }
}

UI:

[HttpPost]
public ActionResult Post(UserViewModel model)
{
    UserIdentity user = MapUser(model);
    var userManager = new IdentityUserManager();
    userManager.Add(user);

    return View(new UserViewModel());
}

(这并非完全在Visual Studio中编写,所以请原谅任何拼写错误。)

虽然这段代码中可能存在更多的抽象,但在此处撰写整个解决方案是荒谬的。例如,您也可以使用工作单元模式,它与存储库模式非常配合。因此,请将其视为示例,而不是实现此设置的完整指南。事情比这个示例要干净得多。

如果您想深入了解这些模式的实现,请务必查看Plural Sight上John Papa的Single Page Apps课程。他在解释这些模式的好处及其如何实现方面做得非常出色。


2
谢谢你的@bump!我的意思是使用存储库模式值得吗?如果是这样,您会如何在单独的项目中实现它。我有点困惑每个“层”如何粘合在一起,我没有找到任何教程(针对ASP.NET MVC)来解释这个问题,并提供代码示例。我有以下内容:WebApp.Model(其中包含所有POCO类) WebApp.ViewModel(其中包含带有数据属性的视图模型) WebApp.Controllers WebApp.Views逻辑放在哪里?即GetAllUsers()我很想看一个关于ASP.NET MVC分层/关注点分离的教程。 - teh0wner
1
@teh0wner 我的示例使用不同的项目(存储库在数据层中)。我认为值得使用存储库。John Papa提到的课程是关于MVC分离关注点的优秀教程(你可以通过PluralSight获得免费试用)。所以去看一下吧。 - Aage
1
看了一下教程,必须承认它非常棒。不过有一个问题.. IdentityUser应该放在哪里?由于它需要引用EntityFramework,所以它并不是一个POCO类。 - teh0wner
@teh0wner 为什么不呢?你可以将你的POCO作为Code First Entity模型使用。你可以添加属性和其他东西。 - Aage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接