微风在哪里适合ntier建筑

时间:2014-11-19 21:07:09

标签: angularjs entity-framework-4 breeze repository-pattern hottowel

我正在尝试使用我现有的架构来适应breezeJS。我有一个像

这样的结构
  1. html / JS / Angular :: based view with hot-towel angular。
  2. web api controllers ::视图调用的对象。
  3. 服务层::从Web api调用。任何业务逻辑都在这里。
  4. 工作单元::和(如果)业务逻辑需要与其称为UOW的CRUD的数据库进行通信。
  5. 存储库模式:: UOW实际上是包装存储库。然后repositores与DbContexts交谈。
  6. 现在我已经能够将正常的存储库实现转换为使用

    的实现
    public EFContextProvider<MyContext> DbContext { get; set; }
    

    而不仅仅是DbContext,我也使用UOW中的字符串属性公开MetaData,并使用DbContext.Context.SomeEntity返回IQueryables

    问题1:我是否正确? 问题2:大多数微风示例都建议使用一个SaveChanges方法,该方法为您提供所有已更改的实体,并且它将立即保留它。如果我想在添加,更新和删除之前触发某些业务逻辑,该怎么办?我想称之为AddSomething服务方法,并希望将特定类型的实体发送到AddSomething并在持久性之前运行一些业务逻辑。我怎么把它放在一起。

    我的代码看起来像

      [BreezeController]//This is the controller 
    public class BreezeController : ApiController
    {
        private readonly ISomeService someService;
        public BreezeController(ISomeService someService)
        {
            this.someService = someService;
        }
        // ~/breeze/todos/Metadata 
        [HttpGet]
        public string Metadata()
        {
            return someService.MetaData();
        }
    
        // ~/breeze/todos/Todos
        // ~/breeze/todos/Todos?$filter=IsArchived eq false&$orderby=CreatedAt 
        [HttpGet]
        public IQueryable<Node> Nodes()
        {
            return nodesService.GetAllNodes().AsQueryable();
        }
    
        // ~/breeze/todos/SaveChanges
        //[HttpPost]
        //public SaveResult SaveChanges(JObject saveBundle)
        //{
        //    return _contextProvider.SaveChanges(saveBundle);
        //}
    

    以下是服务

     public class SomeService : BaseService, ISomeService
    {
        private readonly IUow Uow;
    
        public SomeService(IUow Uow)
            : base(Uow)
        {
            this.Uow = Uow;
        }
        public IEnumerable<Something> GetAllNodes()
        {
            return Uow.Somethings.GetAll();
        }
    }
    

    每个服务都可以通过base公开一个属性。这实际上是元数据

    public class BaseService : IBaseService
    {
        private readonly IUow Uow;
        public BaseService(IUow Uow)
        {
            this.Uow = Uow;
        }
        public string MetaData()
        {
            return Uow.MetaData;
        }
    }
    

    和我的UOW看起来像

        public class VNUow : IUow, IDisposable
    {
        public VNUow(IRepositoryProvider repositoryProvider)
        {
            CreateDbContext();
    
            repositoryProvider.DbContext = DbContext;
            RepositoryProvider = repositoryProvider;       
        }
    
        // Code Camper repositories
    
        public IRepository<Something> NodeGroup { get { return GetStandardRepo<Something>(); } }
       } }
        public IRepository<Node> Nodes { get { return GetStandardRepo<Node>(); } }
        /// <summary>
        /// Save pending changes to the database
        /// </summary>
        public void Commit()
        {
            //System.Diagnostics.Debug.WriteLine("Committed");
            DbContext.Context.SaveChanges();
        }
        public string MetaData   // the Name property
        {
            get
            {
                return DbContext.Metadata();
            }
        }
        protected void CreateDbContext()
        {
        //    DbContext = new VNContext();
    
            DbContext = new EFContextProvider<VNContext>();
            // Load navigation properties always if it is true
            DbContext.Context.Configuration.LazyLoadingEnabled = false;
    
    
            // Do NOT enable proxied entities, else serialization fails
            DbContext.Context.Configuration.ProxyCreationEnabled = true;
    
            // Because Web API will perform validation, we don't need/want EF to do so
            DbContext.Context.Configuration.ValidateOnSaveEnabled = false;
    
            //DbContext.Configuration.AutoDetectChangesEnabled = false;
            // We won't use this performance tweak because we don't need 
            // the extra performance and, when autodetect is false,
            // we'd have to be careful. We're not being that careful.
        }
    
        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 EFContextProvider<VNContext> 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.Context.Dispose();
                }
            }
        }
    
        #endregion
    }
    

    最后Repository Implementaion看起来像

       public class EFRepository<T> : IRepository<T> where T : class
    {
        public EFRepository(EFContextProvider<VNContext> dbContext)
        {
            if (dbContext == null)
                throw new ArgumentNullException("dbContext");
            DbContext = dbContext;
            DbSet = DbContext.Context.Set<T>();
        }
    
        protected EFContextProvider<VNContext> DbContext { get; set; }
    
        protected DbSet<T> DbSet { get; set; }
    
        public virtual IQueryable<T> GetAll()
        {
            return DbSet;
        }
        public virtual IQueryable<T> GetAllEagerLoad(params Expression<Func<T, object>>[] children)
        {
            children.ToList().ForEach(x => DbSet.Include(x).Load());
            return DbSet;
        }
        public virtual IQueryable<T> GetAllEagerLoadSelective(string[] children)
        {
            foreach (var item in children)
            {
                DbSet.Include(item);
            }
            return DbSet;
        }
        public virtual IQueryable<T> GetAllLazyLoad()
        {
            return DbSet;
        }
        public virtual T GetById(int id)
        {
            //return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
    
            return DbSet.Find(id);
        }
        public virtual T GetByIdLazyLoad(int id, params Expression<Func<T, object>>[] children)
        {
            children.ToList().ForEach(x => DbSet.Include(x).Load());
    
            return DbSet.Find(id);
        }
        public virtual void Add(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Context.Entry(entity);
            if (dbEntityEntry.State != EntityState.Detached)
            {
                dbEntityEntry.State = EntityState.Added;
            }
            else
            {
                DbSet.Add(entity);
            }
        }
    
        public virtual void Update(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Context.Entry(entity);
            if (dbEntityEntry.State == EntityState.Detached)
            {
                DbSet.Attach(entity);
            }
            dbEntityEntry.State = EntityState.Modified;
        }
    
        public virtual void Delete(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Context.Entry(entity);
            if (dbEntityEntry.State != EntityState.Deleted)
            {
                dbEntityEntry.State = EntityState.Deleted;
            }
            else
            {
                DbSet.Attach(entity);
                DbSet.Remove(entity);
            }
        }
    
        public virtual void Delete(int id)
        {
            var entity = GetById(id);
            if (entity == null) return; // not found; assume already deleted.
            Delete(entity);
        }
    }
    

2 个答案:

答案 0 :(得分:1)

这个问题的大部分都是广泛的问题,答案主要是以意见为基础......说,这是我的两分钱:保持简单。仔细考虑您是否真的需要3,4和5,尤其是您是否需要自己实现UoW或Repository Pattern。 EF DbContext实现了两者,如果需要,可以直接在控制器中使用它。

如果你有自定义逻辑需要在savechanges之前执行,则使用拦截器方法之一:BeforeSaveEntity或BeforeSaveEntites。这是这些方法的文档:

http://www.getbreezenow.com/documentation/contextprovider#BeforeSaveEntity

答案 1 :(得分:0)

Breeze支持&#34;命名保存&#34;您可以在每个保存的基础上指定特定服务器端点的名称(即您的服务方法)。参见:

http://www.getbreezenow.com/documentation/saving-changes

在您的客户端上看起来像这样。

var saveOptions = new SaveOptions({ resourceName: "CustomSave1" }); 
em.saveChanges(entitiesToSave, saveOptions).then(function (saveResult) {
  // .. do something interesting.

}

并在您的服务器上

[HttpPost]
public SaveResult CustomSave1(JObject saveBundle) {
  ContextProvider.BeforeSaveEntityDelegate = CustomSave1Interceptor;
  return ContextProvider.SaveChanges(saveBundle);
}

private Dictionary<Type, List<EntityInfo>> CustomSave1Interceptor(Dictionary<Type, List<EntityInfo>> saveMap) {
  // In this method you can
  //   1) validate entities in the saveMap and optionally throw an exception
  //   2) update any of the entities in the saveMap
  //   3) add new entities to the saveMap
  //   4) delete entities from the save map.
  // For example
  List<EntityInfo> fooInfos;
  if (!saveMap.TryGetValue(typeof(Foo), out fooEntities)) {
     // modify or delete any of the fooEntites    
     // or add new entityInfo instances to the fooEntities list.
  }

}