【问题标题】:DataAccessLayer and organize solutionDataAccessLayer 和组织解决方案
【发布时间】:2016-12-04 21:14:22
【问题描述】:

我有一个 MVC 解决方案:

在我的不同文件中:

Library.DataAccessLayer.LibraryContext.cs :

namespace Library.DataAccessLayer
{
    public class LibraryContext : DbContext
    {
        public LibraryContext() : base("DefaultConnection")
        {
        }

        public DbSet<Book> Books { get; set; }
        public DbSet<Author> Authors { get; set; }
    }
}

Library.DataAccessLayer.Models.Author.cs :

namespace Library.DataAccessLayer.Models
{
    public class Author
    {
        [Key]
        public int AuthorID { get; set; }

        [Required]
        [StringLength(50)]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        .........

    }

}

Library.DataAccessLayer.Repositories.AuthorRepository.cs :

namespace Library.DataAccessLayer.Repositories
{
    public class AuthorRepository : IDisposable, IAuthorRepository
    {
        private LibraryContext context;

        public AuthorRepository(LibraryContext context)
        {
            this.context = context;
        }

        public IEnumerable<Author> GetAuthors()
        {
            return context.Authors.ToList();
        }

        public Author GetAuthorById(int id)
        {
            return .........
        }

        ............
    }
}

在 Library.Controllers.AuthorController 中:

namespace Library.Controllers
{
    public class AuthorController : Controller
    {
        private IAuthorRepository authorRepository;

        public AuthorController()
        {
            this.authorRepository = new AuthorRepository(new LibraryContext());
        }

        public ActionResult Index()
        {
            var authors = authorRepository.GetAuthors();

            return View(authors);
        }
    }
 }

1/ 这个架构是连贯的?

2/ 为在我的存储库类中实现的存储库声明接口真的有用吗?

3/在我的AuthorRepository中,LibraryContext的声明和调用是否正确?

4/ 在我的 AuthorController 中,我对 AuthorRepository 的声明和调用是否正确?

5/ 我们可以将文件 LibraryContext 放在哪个文件夹中? (如有必要和有用)

6/ 将存储库接口和存储库类分组在同一个文件夹中好吗?如果不是,如何对各个文件夹进行分隔和命名?

7/ 如何改进?

我需要你的建议。

谢谢

【问题讨论】:

    标签: c# entity-framework-6 repository-pattern


    【解决方案1】:
    1. 我发现架构很简单,这很好,也许随着应用程序的增长,您需要更多层
    2. 是的,非常好,特别是如果您要使用依赖注入,这就引出了下一个问题。
    3. 您的实现是正确的,至于依赖关系,您应该使用一些设计模式,同样,依赖注入或工厂。您的所有依赖项都应在外部实例化。
    4. 这个应该和上一个一样,repository应该在外面实例化。
    5. 该结构应该可以满足您的需求,但我发现here 中的示例非常有用
    6. 许多开发人员都是这样做的,有些开发人员也这样做,有些开发人员(例如我)将它们保存在单独的文件中,我个人在我的存储库旁边创建了一个“合同”文件夹并将接口保存在那里。
    7. 找到适合您的约定的最佳方法是阅读其他开发人员的代码,在那里您会发现许多样式、结构、架构和模式实现。

    我希望你觉得这很有用,愿原力与你同在

    【讨论】:

    • 如果我想创建一个RepositoryFactory 或DbContextFactory,我的不同文件应该放在哪里?在 dal 项目中?如何命名托管文件的目录?谢谢!
    • 为每个表(实体/模型)创建存储库是否正确?即使存储库中只有一种方法?
    • 我认为如果你创建一个通用存储库会更好,使用Context.Set&lt;T&gt;()你可以实现它,你可以将工厂设置在与类相同的命名空间中。
    【解决方案2】:

    这个问题更适合Codereview website,但我认为这里值得回答:

    1. 存储库 很好,但您还应该考虑定义一个服务层。服务负责使用存储库聚合信息并使用服务模型提供此信息。发回数据模型(例如Authors)可能会导致麻烦,因为:

      • 如果导航属性创建循环,序列化可能会失败
      • 您想提供更多与数据层无关的信息(例如一些计算的东西)

    例子:

    class AuthorServiceModel
    {
        int AuthorId { get; set; }
        string FirstName { get; set; }
        // ...
    }
    
    class LibraryService : ILibraryService      // if DI is used
    {
        public AuthorServiceModel GetAuthorById(int id)
        {
            // error handling/logging may be put here, if an invalid id is provided
    
            var author = context.Authors.Get(id);
            // auto mapping can be used to avoid the typing - check http://automapper.org/
            var sm = new AuthorServiceModel { AuthorId = author.AuthorId, FirstName = author.FirstName };
            return sm;
        }
    
        // 
    }
    
    The controller will never have to know about your data access layer
    

    2) 存储库统一 - 如果您的大多数存储库只执行标准操作(获取所有、通过标识符获取、更新实体、删除实体等),您可以定义一个通用类型存储库这可以帮助您避免重复:

    class Repository<T> : IRepository<T>
    {
        private LibraryContext context;
    
        public IQueryable<T> All => context.Set<T>().AsQueryable();
    
        public IQueryable<T> AllNoTracking => context.Set<T>().AsNoTracking();
    
        public T Get(int id)
        {
            return context.Set<T>().Find(id);
        }
    
        // other methods
    }
    

    3) 使用依赖注入 - DI(例如Ninject)时,实现接口可能很有用。这消除了类之间的一些耦合,还允许自动测试(绑定可以更改为模拟对象)。例如:

    public class LibraryContext : DbContext, ILibraryContext
    {
        public LibraryContext() : base("DefaultConnection")
        {
        }
    
        // other methods here
    }
    
    public class AuthorRepository : IDisposable, IAuthorRepository
    {
        private ILibraryContext context;
    
        // the context will be injected and should not be provided by the caller, if DI is used
        public AuthorRepository(ILibraryContext context)
        {
            this.context = context;
        }
    
        // other methods come here
    }
    
    public class AuthorController : Controller
    {
        // this allows for automatic injection based on defined bindings
        [Inject]
        public IAuthorRepository authorRepository { get; set; }
    
        public AuthorController()
        {
            // no need for this, as DI takes care of the initialization
            // also, controller does not have to know about your data access classes
            // this.authorRepository = new AuthorRepository(new LibraryContext());
        }
    
        public ActionResult Index()
        {
            var authors = authorRepository.GetAuthors();
            return View(authors);
        }
    }
    

    4) 文件分组是个人喜好问题,但我通常建议在语义上摸索它们(在文件夹中执行类似工作的所有类和接口)。此外,数据上下文和存储库非常耦合,它们可以驻留在同一个项目/程序集中。

    此外,服务可以在它们自己的项目/程序集中分离。

    注意:要进行更全面的分析,请考虑提供与您的模式相关的所有代码并将您的问题发布在 Codereview 上(它们处理完整且有效的代码,而不仅仅是片段)。很有可能有人会涵盖从命名到模式的所有主题。

    【讨论】:

    • 该问题不包含工作代码,与 CR 无关。
    猜你喜欢
    • 2012-03-20
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多