循环参考+ IoC

时间:2014-01-13 22:01:01

标签: asp.net-mvc inversion-of-control unity-container circular-dependency

我遇到这种情况:

Web项目 - 使用Unity 3 IoC调用Business类。 Web项目没有看到Business Project。它只是引用了合同项目。

namespace Biblioteca.Web.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();

            var Autor = Inject.Resolve<IAutorBO>();
        }
    }
}

业务项目 - 这里我使用Unity 3 IoC指向数据项目中的AutorDO类(见下文)。业务项目没有看到数据项目。

namespace Biblioteca.Data
{
    public sealed partial class AutorBO : IAutorBO
    {                
        #region Atributos

        private IAutorDO AutorDO = Inject.Resolve<IAutorDO>();

        #endregion

        #region Métodos Interface

        public IQueryable<DTOAutor> GetAll()
        {
            return AutorDO.GetAll();
        }

        public DTOAutor GetById(int id)
        {
            return AutorDO.GetById(id);
        }

        void IAutorBO.Insert(DTOAutor dto)
        {
            AutorDO.Insert(dto);
        }

        void IAutorBO.Delete(DTOAutor dto)
        {
            AutorDO.Delete(dto);
        }

        void IAutorBO.Update(DTOAutor dto)
        {
            AutorDO.Update(dto);
        }

        //IQueryable<DTOAutor> IAutorBO.SearchFor(Expression<Func<Autor, bool>> predicate)
        //{
        //    return AutorDO.SearchFor(predicate);
        //}

        IQueryable<DTOAutor> IAutorBO.GetAll()
        {
            return AutorDO.GetAll();
        }

        DTOAutor IAutorBO.GetById(int id)
        {
            return AutorDO.GetById(id);
        }

        #endregion

        #region Outros Métodos

        #endregion
    }
}

数据访问项目 - 这是我的数据项目。

namespace Biblioteca.Data
{
    public sealed partial class AutorDO : IAutorDO
    {
        #region Atributos

        Repository<Autor> repository = new Repository<Autor>();

        #endregion

        #region Implementações Interface

        /// <summary>
        /// Implementação do método de interface Insert
        /// </summary>
        /// <param name="dto"></param>
        void IAutorDO.Insert(Transport.DTOAutor dto)
        {
            Autor entity = AssemblerAutor.ToEntity(dto);
            repository.Insert(entity);
        }

        /// <summary>
        /// Implementação do método de interface Delete
        /// </summary>
        /// <param name="dto"></param>
        void IAutorDO.Delete(Transport.DTOAutor dto)
        {
            Autor entity = AssemblerAutor.ToEntity(dto);
            repository.Delete(entity);
        }

        /// <summary>
        /// Implementação do método de interface Update
        /// </summary>
        /// <param name="dto"></param>
        void IAutorDO.Update(Transport.DTOAutor dto)
        {
            Autor entity = AssemblerAutor.ToEntity(dto);
            repository.Update(entity);
        }

        /// <summary>
        /// Implementação do método de interface SearchFor
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        //IQueryable<Transport.DTOAutor> IAutorDO.SearchFor(Expression<Func<Autor, bool>> predicate)
        //{
        //    IQueryable<Autor> list = repository.SearchFor(predicate);
        //    IQueryable<Transport.DTOAutor> dtoList = (IQueryable<Transport.DTOAutor>)AssemblerAutor.ToDTOs(list);
        //    return dtoList;
        //}

        /// <summary>
        /// Implementação do método de interface GetAll
        /// </summary>
        /// <returns></returns>
        IQueryable<Transport.DTOAutor> IAutorDO.GetAll()
        {
            IQueryable<Autor> list = repository.GetAll();
            IQueryable<Transport.DTOAutor> dtoList = (IQueryable<Transport.DTOAutor>)AssemblerAutor.ToDTOs(list);
            return dtoList;
        }

        /// <summary>
        /// Implementação do método de interface GetById
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Transport.DTOAutor IAutorDO.GetById(int id)
        {
            Autor entity = new Autor();
            Transport.DTOAutor dto = new Transport.DTOAutor();

            using (var ctx = new BibliotecaContext())
            {
                entity = repository.GetById(id);
                dto = AssemblerAutor.ToDTO(entity);
            }

            return dto;
        }

        #endregion
    }
}

业务和数据项目均引用了合同项目,该项目包含用于实施IoC的所有Unity 3 IoC接口。以下是用于实现IoC的接口:

namespace Biblioteca.Contracts
{
    public interface IAutorBO
    {
        #region Métodos CRUD

        void Insert(DTOAutor dto);
        void Delete(DTOAutor dto);
        void Update(DTOAutor dto);
        //IQueryable<DTOAutor> SearchFor(Expression<Func<Autor, bool>> predicate);
        IQueryable<DTOAutor> GetAll();
        DTOAutor GetById(int id);

        #endregion
    }
}

namespace Biblioteca.Contracts
{
    public interface IAutorDO
    {
        #region Métodos CRUD

        void Insert(DTOAutor dto);
        void Delete(DTOAutor dto);
        void Update(DTOAutor dto);
        //IQueryable<DTOAutor> SearchFor(Expression<Func<Autor, bool>> predicate);
        IQueryable<DTOAutor> GetAll();
        DTOAutor GetById(int id);

        #endregion
    }
}

作为补充,我使用通用存储库,如下所示:

namespace Biblioteca.Data
{
    /// <summary>
    /// Interface para classe genérica para métodos CRUD
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IRepository<T>
    {
        void Insert(T entity);
        void Delete(T entity);
        void Update(T entity);
        IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
        IQueryable<T> GetAll();
        T GetById(int id);
    }
}

namespace Biblioteca.Data
{
    /// <summary>
    /// Classe genérica para métodos CRUD da camada Data
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Repository<T> : IRepository<T> where T : class 
    {
        #region Attributes

        protected DbSet<T> dbset;
        protected DbContext ctx;

        #endregion

        #region Constructor

        public Repository()
        { }

        public Repository(DbContext ctx)
        {
            this.ctx = ctx;
            dbset = ctx.Set<T>();
        }

        #endregion

        #region IRepository<T> Members

        public void Insert(T entity)
        {
            if (dbset.Contains(entity))
            {
                Update(entity);
            }
            else
            {
                dbset.Add(entity);
            }
        }

        public void Delete(T entity)
        {
            dbset.Remove(entity);
        }

        public void Update(T entity)
        {
            using (ctx)
            {
                ctx.Set<T>().Attach(entity);
                ctx.SaveChanges();
            }
        }

        public IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate)
        {
            return dbset.Where(predicate);
        }

        public IQueryable<T> GetAll()
        {
            return dbset;
        }

        public T GetById(int id)
        {
            return dbset.Find(id);
        }

        #endregion
    }
}

请注意,我在所有类中都有一个注释方法。此方法无法实现,因为它会导致循环依赖。

我有引用合同项目的数据项目。但是我不能使用“SearchFor”方法,因为它需要Data Project中的Entity Autor。

请注意,Business和Data都需要查看Entity类,因为我有相同的方法签名。

我需要一些方法来允许以这种方式使用IoC,其中Web不引用Business和Business而不引用Data,并且能够创建其他方法,我可以将Entity作为参数传递。

有什么建议吗?我已经尝试创建第三个项目并指向它,但我不能使它工作。是否可以使用反射?如果可能,怎么样?

我将不胜感激。

1 个答案:

答案 0 :(得分:0)

如果您有循环依赖关系,那么您应该修改您的体系结构。

如果您需要“使数据项目引用合同项目”,则Contract不能引用数据来获取实体。您说“业务和数据需要查看实体类”,所以为什么不将实体Autor保留在实体项目中。

数据    - &GT;参考合同    - &GT;参考实体 合同    - &GT;引用实体

或者作为替代方案,在Contract项目中定义您的实体而不是Data。