是否有使用及QUOT任何优势;库工厂"与ASP.NET MVC4和Entity Framework? [英] Is there any advantage in using a "repository factory" with ASP.NET MVC4 and Entity Framework?

查看:166
本文介绍了是否有使用及QUOT任何优势;库工厂"与ASP.NET MVC4和Entity Framework?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开发一个应用程序,我开始为我的基地由约翰爸爸的例子使用一些code。展望在网络上,我发现这个同样的code,它出现在一个问题的答案上
堆栈溢出。这里有一个问题:

I am developing an application and I started to use as my base some code from an example by John Papa. Looking on the web I found this same code and it appears in an answer to a question on Stackoverflow. Here is the question:

<一个href=\"http://stackoverflow.com/questions/12814254/how-to-de-attach-an-entity-from-a-context-in-entity-framework\">How从实体框架上下文来取消附加的实体?

这是在回答这是由下式给出:Syner codeR

It's in the answer that was given by: SynerCoder

答案的一个部分表明被用于提供从高速缓存库的字典的信息库的下列类。有人能帮助我,并告诉我是真的
在这样做的优点。据我所知,code,但不能看到库保持在字典中的点。这岂不是每一个新的网页请求将看到一个案例
空字典,并有获取/做出新的存储库反正。

One part of the answer suggests the following class that is used to provide a repository from a dictionary of cached repositories. Can someone help me out and tell me is there really an advantage in doing this. I understand the code but can't see the point of keeping repositories in a dictionary. Would it not be the case that every new web request would see an empty dictionary and have to get / make a new repository anyway.

Data/Helpers/IRepositoryProvider.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using Data.Contracts;

namespace Data.Helpers
{
    /// <summary>
    /// A maker of Repositories.
    /// </summary>
    /// <remarks>
    /// An instance of this class contains repository factory functions for different types.
    /// Each factory function takes an EF <see cref="DbContext"/> and returns
    /// a repository bound to that DbContext.
    /// <para>
    /// Designed to be a "Singleton", configured at web application start with
    /// all of the factory functions needed to create any type of repository.
    /// Should be thread-safe to use because it is configured at app start,
    /// before any request for a factory, and should be immutable thereafter.
    /// </para>
    /// </remarks>
    public class RepositoryFactories
    {
        /// <summary>
        /// Return the runtime repository factory functions,
        /// each one is a factory for a repository of a particular type.
        /// </summary>
        /// <remarks>
        /// MODIFY THIS METHOD TO ADD CUSTOM FACTORY FUNCTIONS
        /// </remarks>
        private IDictionary<Type, Func<DbContext, object>> GetFactories()
        {
            return new Dictionary<Type, Func<DbContext, object>>
                {
                   //If you have an custom implementation of an IRepository<T>
                   //{typeof(IArticleRepository), dbContext => new ArticleRepository(dbContext)}
                };
        }

        /// <summary>
        /// Constructor that initializes with runtime repository factories
        /// </summary>
        public RepositoryFactories()
        {
            _repositoryFactories = GetFactories();
        }

        /// <summary>
        /// Constructor that initializes with an arbitrary collection of factories
        /// </summary>
        /// <param name="factories">
        /// The repository factory functions for this instance. 
        /// </param>
        /// <remarks>
        /// This ctor is primarily useful for testing this class
        /// </remarks>
        public RepositoryFactories(IDictionary<Type, Func<DbContext, object>> factories)
        {
            _repositoryFactories = factories;
        }

        /// <summary>
        /// Get the repository factory function for the type.
        /// </summary>
        /// <typeparam name="T">Type serving as the repository factory lookup key.</typeparam>
        /// <returns>The repository function if found, else null.</returns>
        /// <remarks>
        /// The type parameter, T, is typically the repository type 
        /// but could be any type (e.g., an entity type)
        /// </remarks>
        public Func<DbContext, object> GetRepositoryFactory<T>()
        {

            Func<DbContext, object> factory;
            _repositoryFactories.TryGetValue(typeof(T), out factory);
            return factory;
        }

        /// <summary>
        /// Get the factory for <see cref="IRepository{T}"/> where T is an entity type.
        /// </summary>
        /// <typeparam name="T">The root type of the repository, typically an entity type.</typeparam>
        /// <returns>
        /// A factory that creates the <see cref="IRepository{T}"/>, given an EF <see cref="DbContext"/>.
        /// </returns>
        /// <remarks>
        /// Looks first for a custom factory in <see cref="_repositoryFactories"/>.
        /// If not, falls back to the <see cref="DefaultEntityRepositoryFactory{T}"/>.
        /// You can substitute an alternative factory for the default one by adding
        /// a repository factory for type "T" to <see cref="_repositoryFactories"/>.
        /// </remarks>
        public Func<DbContext, object> GetRepositoryFactoryForEntityType<T>() where T : class
        {
            return GetRepositoryFactory<T>() ?? DefaultEntityRepositoryFactory<T>();
        }

        /// <summary>
        /// Default factory for a <see cref="IRepository{T}"/> where T is an entity.
        /// </summary>
        /// <typeparam name="T">Type of the repository's root entity</typeparam>
        protected virtual Func<DbContext, object> DefaultEntityRepositoryFactory<T>() where T : class
        {
            return dbContext => new EFRepository<T>(dbContext);
        }

        /// <summary>
        /// Get the dictionary of repository factory functions.
        /// </summary>
        /// <remarks>
        /// A dictionary key is a System.Type, typically a repository type.
        /// A value is a repository factory function
        /// that takes a <see cref="DbContext"/> argument and returns
        /// a repository object. Caller must know how to cast it.
        /// </remarks>
        private readonly IDictionary<Type, Func<DbContext, object>> _repositoryFactories;
    }
}

这里的code调用该工厂:

Here's the code that calls the factory:

using System;
using Data.Contracts;
using Data.Helpers;
using Models;

namespace Data
{
    /// <summary>
    /// The "Unit of Work"
    ///     1) decouples the repos from the controllers
    ///     2) decouples the DbContext and EF from the controllers
    ///     3) manages the UoW
    /// </summary>
    /// <remarks>
    /// This class implements the "Unit of Work" pattern in which
    /// the "UoW" serves as a facade for querying and saving to the database.
    /// Querying is delegated to "repositories".
    /// Each repository serves as a container dedicated to a particular
    /// root entity type such as a <see cref="Url"/>.
    /// A repository typically exposes "Get" methods for querying and
    /// will offer add, update, and delete methods if those features are supported.
    /// The repositories rely on their parent UoW to provide the interface to the
    /// data layer (which is the EF DbContext in this example).
    /// </remarks>
    public class UnitOfWork : IUnitOfWork, IDisposable
    {
        public UnitOfWork(IRepositoryProvider repositoryProvider)
        {
            CreateDbContext();

            repositoryProvider.DbContext = DbContext;
            RepositoryProvider = repositoryProvider;       
        }

        // Repositories
        public IRepository<Event> Events { get { return GetStandardRepo<Event>(); } }
        public IRepository<Candidate> Candidates { get { return GetStandardRepo<Candidate>(); } }

        /// <summary>
        /// Save pending changes to the database
        /// </summary>
        public void Commit()
        {
            //System.Diagnostics.Debug.WriteLine("Committed");
            DbContext.SaveChanges();
        }

        protected void CreateDbContext()
        {
            DbContext = new UnicornsContext();

            // Do NOT enable proxied entities, else serialization fails
            DbContext.Configuration.ProxyCreationEnabled = false;

            // Load navigation properties explicitly (avoid serialization trouble)
            DbContext.Configuration.LazyLoadingEnabled = false;

            // Because Web API will perform validation, I don't need/want EF to do so
            DbContext.Configuration.ValidateOnSaveEnabled = false;
        }

        protected IRepositoryProvider RepositoryProvider { get; set; }

        private IRepository<T> GetStandardRepo<T>() where T : class
        {
            return RepositoryProvider.GetRepositoryForEntityType<T>();
        }
        private T GetRepo<T>() where T : class
        {
            return RepositoryProvider.GetRepository<T>();
        }

        private UnicornsContext DbContext { get; set; }

        #region IDisposable

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (DbContext != null)
                {
                    DbContext.Dispose();
                }
            }
        }

        #endregion
    }
}

在我看来,该工厂使事情变得更加复杂,他们需要的是。我是正确,我应该做一个简单的方法,如用这样的:

It seems to me that the factory makes things more complicated that they need be. Am I correct and should I do this a simpler way such as with something like:

private IRepository<xx> = new GenericRepository<xx>(dbContext);

还有一点。在我的应用我使用统一。所以,会是更容易只需指定在构造函数中所需的资料库,并有统一创建库我。如果我这样做,那么有没有一种方法,我可以传递周围的DbContext,以便它可以由Unity在创建资源库时,可以使用?采用了统一任何人创建库这样?

One more point. In my application I am using Unity. So would it be even easier to just specify the needed repositories in the constructor and have Unity create the repositories for me. If I did this then is there a way I could pass around the dbContext so it could be used by Unity when creating the repository? Has anyone used Unity to create repositories like this?

推荐答案

确定。这是我最好的拍摄:

OK. Here's my best shot:


  1. 保存库在缓存中的一点是要确保每个请求的仓库只是启动一次。该库缓存是在 RepositoryProvider 类,由 GetRepositoryForEntityType <暴露在的UnitOfWork / code>方法。这样做的好处是,工作单位不关心缓存或存储库的创建。

  1. The point of keeping repositories in a cache is to ensure that the repository is only initiated once per request. The repository cache is in the RepositoryProvider class and is exposed to the UnitOfWork by the GetRepositoryForEntityType method. So the advantage is that the unit of work is not concerned with caching or creation of repositories.

RepositoryProvider 类实例化每个工作单元一次。 (NB - 希望创造新的为每个请求的资源库)。在 RepositoryProvider 使用类型作为重点保持在仓库的字典。利用具有键入参数通用库基地时,这是好的。但是,如果你已经创建了一个定制的仓库?在这个例子中按类型创建存储库被传递到 RepositoryFactories 通过 MakeRepository 方法类。它的优点是,在创建库是从缓存中分离

The RepositoryProvider class is instantiated once per unit of work. (NB - it is desirable to create the repositories new for every request). The RepositoryProvider keeps the repositories in a dictionary using the type as a key. This is fine when using the generic repository base which has a Type parameter. But what if you have created a custom repository? In this example the creation of repositories by type is handed off to the RepositoryFactories class via the MakeRepository method. The advantage is that creating repositories is separated from caching.

RepositoryFactories 类知道何时创建一个自定义库,因为它包含使用类型作为键和值的函数的字典。该功能自定义库的构造。如果有一个在字典中的值,然后使用该构造,否则仅仅使用了通用基础构造。

The RepositoryFactories class knows when to make a custom repository because it contains a dictionary that uses Type as a key and a function as a value. The function is the constructor for a custom repository. If there's a value in the dictionary then use that constructor otherwise just use the generic base constructor.

这一切都意味着,当你添加实体你没有,除非你创建一个自定义库中修改其中的任何类。当你这样做,所有你需要做的就是在 RepositoryFactories

All this means that as you add entities you do not have to modify any of these classes unless you create a custom repository. And when you do that all you have to do is add an entry to the dictionary in RepositoryFactories

这篇关于是否有使用及QUOT任何优势;库工厂&QUOT;与ASP.NET MVC4和Entity Framework?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆