具有分层 Web 应用程序的实体框架

Posted

技术标签:

【中文标题】具有分层 Web 应用程序的实体框架【英文标题】:Entity Framework with a layered web application 【发布时间】:2014-02-13 23:56:47 【问题描述】:

我知道这个问题似乎已经在这里提出了,但是我有具体的疑问,主要是数据库优先使用,并且在回答的问题中缺少代码示例。

我有这些层:核心、数据和 UI (asp.net mvc)。 我在 MSSQL 中有这些表:Person 和 Contact。

问题 1:在数据层,EDMX 生成 Person 和 Data POCO。我在哪里写像 SearchPersonByCity() 这样的方法?我是否需要在同一数据层中创建另一个 Person 类,仅用于写入数据 CRUD?我怎么做这个?请举个例子(类、命名空间等。不需要整个实际代码)

问题 2:如何在数据层和核心(域模型)之间转换这些数据?我需要在核心(域)类中在哪里创建相同的SearchPersonByCity()?也许只是为这些数据访问方法在核心层创建另一个 Person 类?

请给我一些代码示例,以及大公司在现实生活中的表现,因为它似乎很愚蠢,需要维护大量代码,并且很可能我出错了。

我并不懒惰,我阅读了数百页的 Entity Framework 书籍,这里有问题,我无法弄清楚如何在代码中做到这一点。

【问题讨论】:

【参考方案1】:

在我看来,我会在你的情况下使用存储库模式,所以首先你定义了一个 IRepository 类:

public interface IRepository<T> where T : 

    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(Expression<Func<T, bool>> where);
    T GetById(long id);
    T GetById(string id);
    T Get(Expression<Func<T, bool>> where);

还有一个抽象基 RepositoryBase 类:

public abstract class RepositoryBase<T> where T : class

    private PersonDBEntities dataContext;
    private readonly IDbSet<T> dbset;
    protected RepositoryBase(IDatabaseFactory databaseFactory)
    
        DatabaseFactory = databaseFactory;
        dbset = DataContext.Set<T>();
    

    protected IDatabaseFactory DatabaseFactory
    
        get;
        private set;
    

    protected PersonDBEntities DataContext
    
        get  return dataContext ?? (dataContext = DatabaseFactory.Get()); 
    
    public virtual void Add(T entity)
    
        dbset.Add(entity);
    
    public virtual void Update(T entity)
    
        dbset.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
    
    public virtual void Delete(T entity)
    
        dbset.Remove(entity);
    
    public virtual void Delete(Expression<Func<T, bool>> where)
    
        IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
        foreach (T obj in objects)
        dbset.Remove(obj);
    
    public virtual T GetById(long id)
    
        return dbset.Find(id);
    
    public virtual T GetById(string id)
    
        return dbset.Find(id);
    
    public virtual IEnumerable<T> GetAll()
    
        return dbset.ToList();
    

    //You can return IQueryable if you want to build your expression true later on...
    public virtual IEnumerable<T> Get(Expression<Func<T, bool>> where)
    
        return dbset.Where(where).ToList();
    

还有你的 PersonRepository 类:

public class PersonRepository: RepositoryBase<Person>, IPersonRepository
    
    public PersonRepository(IDatabaseFactory databaseFactory)
        : base(databaseFactory)
        
                   
    
public interface IPersonRepository : IRepository<Person> // Person will be your POCO class


下一步是在您的服务层上,您将定义并实现实际的 SearchPersonByCity() 方法:

public class PersonService : IPersonService

    private readonly IPersonRepository personRepository;
    private readonly IUnitOfWork unitOfWork;

    public PersonService(IPersonRepository personRepository, IUnitOfWork unitOfWork)
    
        this.personRepository = personRepository;
        this.unitOfWork = unitOfWork;
    

    public IEnumerable<Person> SearchPersonByCity(string city)
    
        var persons = personRepository.Get(p => p.City == city);
        return persons;
    

【讨论】:

但有一件事。我的 EDMX 在 Repository 层,对吧?因此,作为您在服务层工作的 POCO Person 类。 UI 层(asp.net mvc)会访问这些 Repository 自动生成的数据实体吗? Repositories 对象将与您的 EDMX 实体模型对象位于同一层。 EDMX 是您的 dbcontext。您的 Repository 基类将包含 dbcontext 的一个实例。您可以将 POCO 类放在域模型层中。 UI 层 (mvc) 只能访问作为包装层的服务层来调用您的存储库方法。 “你可以把你的 POCO 类放在域模型层”怎么样?在您的代码示例中,您将 DATA-MODEL 返回给服务,它会在 UI 中使用 DATA-MODEL,这是错误的。它应该返回域模型或视图模型以在 UI 中工作,对吗?那么,会怎么样呢? 是的,您可以这样做,但在我看来,这有点过度架构。 POCO 类也可以用作您的业务对象。您可能想要添加您的 Person POCO 类的业务对象,并在 SearchPersonByCity 方法中,将 POCO Person 类映射到您的业务 Person 类,改为返回 IEnumerable

以上是关于具有分层 Web 应用程序的实体框架的主要内容,如果未能解决你的问题,请参考以下文章

测试驱动设计和分层架构

n 分层架构中的实体框架 - 要遵循的最佳实践?

用于将自定义查询映射到具有用户定义的键/值对的分层实体的“规范”方法

ASP.Net 分层应用程序 - 在层之间共享实体数据模型

实体框架 - 分层设计 - 将连接字符串放在哪里?

实体框架自引用分层多对多