其中,doese微风适合的nTier架构 [英] where doese breeze fits into ntier architecture

查看:180
本文介绍了其中,doese微风适合的nTier架构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想以适应breezeJS与我现有的架构。我有一个像

的结构

  1. HTML / JS /角::基于使用热毛巾角视图。

  2. 网页API控制器::人的观点电话。

  3. 服务层::正从网页API调用。任何业务逻辑放在这里。

  4. 工作单位::和(If)的业务逻辑,需要倾诉的数据基础调用UOW CRUDs。

  5. Repository模式:: UOW实际上是包装仓库。反过来repositores交谈DbContexts。

Uptill现在我能CONVER正常库执行到使用有一个

 公共EFContextProvider< MyContext> {的DbContext获得;组; }

而不是仅仅的DbContext和我使用的字符串属性与UOW也暴露出元数据,并使用DbContext.Context.SomeEntity返回IQueryables

问题1:我是在正确的轨道?
问题2:大多数的微风例子建议一名SaveChanges方法,让你被改变的所有实体,它会立刻坚持它。如果我想之前触发一些业务逻辑添加,更新和删除。我想打电话给我AddSomething服务方法,并希望有实体的特定类型被发送到AddSomething和持久性之前运行一些业务逻辑。我怎样才能把它在一起。

我的code looksl IKE

  [BreezeController] //这是控制器
公共类BreezeController:ApiController
{
    私人只读ISomeService someService;
    公共BreezeController(ISomeService someService)
    {
        this.someService = someService;
    }
    //〜/微风/待办事项/元
    [HTTPGET]
    公共字符串元数据()
    {
        返回someService.MetaData();
    }    //〜/微风/待办事项/托多斯
    //〜/微风/待办事项/托多斯$ =过滤器EQ的isArchived假放; $排序依据= CreatedAt
    [HTTPGET]
    公众的IQueryable<节点>节点()
    {
        返回nodesService.GetAllNodes()AsQueryable已()。
    }    //〜/微风/待办事项/调用SaveChanges
    // [HttpPost]
    //公共SaveResult的SaveChanges(JObject saveBundle)
    // {
    //返回_contextProvider.SaveChanges(saveBundle);
    //}

下面是服务

 公共类SomeService:BaseService,ISomeService
{
    私人只读IUow UOW;    公共SomeService(IUow UOW)
        :基地(UOW)
    {
        this.Uow = UOW;
    }
    公共IEnumerable的<&东西GT; GetAllNodes()
    {
        返回Uow.Somethings.GetAll();
    }
}

每一次服务都能通过公开基地之一的财产。那其实是元数据

 公共BaseService类:IBaseService
{
    私人只读IUow UOW;
    公共BaseService(IUow UOW)
    {
        this.Uow = UOW;
    }
    公共字符串元数据()
    {
        返回Uow.MetaData;
    }
}

和我UOW看起来像

 公共类VNUow:IUow,IDisposable接口
{
    公共VNUow(IRepositoryProvider repositoryProvider)
    {
        CreateDbContext();        repositoryProvider.DbContext =的DbContext;
        RepositoryProvider = repositoryProvider;
    }    // code露营库    公共IRepository<&东西GT;节点组{{返回GetStandardRepo<&东西GT;(); }}
   }}
    公共IRepository<节点>节点{{返回GetStandardRepo<节点>(); }}
    ///<总结>
    ///保存未决更改数据库
    ///< /总结>
    公共无效的commit()
    {
        //System.Diagnostics.Debug.WriteLine(\"Committed);
        DbContext.Context.SaveChanges();
    }
    公共字符串元数据// Name属性
    {
        得到
        {
            返回DbContext.Metadata();
        }
    }
    保护无效CreateDbContext()
    {
    //的DbContext =新VNContext();        的DbContext =新EFContextProvider< VNContext>();
        //加载导航属性始终如果这是真的
        DbContext.Context.Configuration.LazyLoadingEnabled = FALSE;
        //不要启用代理的实体,否则系列化失败
        DbContext.Context.Configuration.ProxyCreationEnabled = TRUE;        //因为Web API将执行验证,我们并不需要/想EF这样做
        DbContext.Context.Configuration.ValidateOnSaveEnabled = FALSE;        //DbContext.Configuration.AutoDetectChangesEnabled = FALSE;
        //因为我们不需要,我们不会使用这种性能好办法
        //额外的性能,当自动检测是假的,
        //我们必须要小心。我们不是说小心。
    }    保护IRepositoryProvider RepositoryProvider {搞定;组; }    私人IRepository< T> GetStandardRepo< T>()其中T:类
    {
        返回RepositoryProvider.GetRepositoryForEntityType< T>();
    }
    私人ŧGetRepo< T>()其中T:类
    {
        返回RepositoryProvider.GetRepository< T>();
    }    私人EFContextProvider< VNContext> {的DbContext获得;组; }    #区域的IDisposable    公共无效的Dispose()
    {
        处置(真);
        GC.Sup pressFinalize(本);
    }    受保护的虚拟无效的Dispose(BOOL处置)
    {
        如果(处置)
        {
            如果(的DbContext!= NULL)
            {
                DbContext.Context.Dispose();
            }
        }
    }    #endregion
}

到底库Implementaion看起来像

 公共类EFRepository< T> :IRepository< T>其中T:类
{
    公共EFRepository(EFContextProvider< VNContext>的DbContext)
    {
        如果(的DbContext == NULL)
            抛出新的ArgumentNullException(的DbContext);
        的DbContext =的DbContext;
        DbSet = DbContext.Context.Set< T>();
    }    保护EFContextProvider< VNContext> {的DbContext获得;组; }    保护DbSet< T> DbSet {搞定;组; }    公共虚拟的IQueryable< T>得到所有()
    {
        返回DbSet;
    }
    公共虚拟的IQueryable< T> GetAllEagerLoad(PARAMS前pression<&Func键LT; T,对象>> []子女)
    {
        。children.ToList()的ForEach(X => DbSet.Include(x)的.Load());
        返回DbSet;
    }
    公共虚拟的IQueryable< T> GetAllEagerLoadSelective(字符串[]子女)
    {
        的foreach(儿童VAR项)
        {
            DbSet.Include(项目);
        }
        返回DbSet;
    }
    公共虚拟的IQueryable< T> GetAllLazyLoad()
    {
        返回DbSet;
    }
    公众实际的t GetById(INT ID)
    {
        //返回DbSet.FirstOrDefault(predicateBuilder.GetById predicate< T>(ID));        返回DbSet.Find(ID);
    }
    公众实际的t GetByIdLazyLoad(INT ID,则params防爆pression<&Func键LT; T,对象>> []子女)
    {
        。children.ToList()的ForEach(X => DbSet.Include(x)的.Load());        返回DbSet.Find(ID);
    }
    公共虚拟无效添加(T实体)
    {
        DbEntityEntry dbEntityEntry = DbContext.Context.Entry(实体);
        如果(dbEntityEntry.State!= EntityState.Detached)
        {
            dbEntityEntry.State = EntityState.Added;
        }
        其他
        {
            DbSet.Add(实体);
        }
    }    公共虚拟无效更新(T实体)
    {
        DbEntityEntry dbEntityEntry = DbContext.Context.Entry(实体);
        如果(dbEntityEntry.State == EntityState.Detached)
        {
            DbSet.Attach(实体);
        }
        dbEntityEntry.State = EntityState.Modified;
    }    公共虚拟无效删除(T实体)
    {
        DbEntityEntry dbEntityEntry = DbContext.Context.Entry(实体);
        如果(dbEntityEntry.State!= EntityState.Deleted)
        {
            dbEntityEntry.State = EntityState.Deleted;
        }
        其他
        {
            DbSet.Attach(实体);
            DbSet.Remove(实体);
        }
    }    公共虚拟无效删除(INT ID)
    {
        变种实体= GetById(ID);
        如果(实体== NULL)回报; // 未找到;假设已被删除。
        删除(实体);
    }
}


解决方案

微风支持命名保存,你在指定特定的服务器端点(即您的服务方法)的名称保存每基础。参见:

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

这将是这个样子你的客户端上。

  VAR saveOptions =新SaveOptions({资源名称:CustomSave1});
em.saveChanges(entitiesToSave,saveOptions)。然后(功能(saveResult){
  // ..做一些有趣的事情。}

和您的服务器上。

  [HttpPost]
公共SaveResult CustomSave1(JObject saveBundle){
  ContextProvider.BeforeSaveEntityDelegate = CustomSave1Interceptor;
  返回ContextProvider.SaveChanges(saveBundle);
}私人字典<类型,列表与LT; EntityInfo>> CustomSave1Interceptor(词典<类型,列表与LT; EntityInfo>> saveMap){
  //在这个方法中,你可以
  // 1)验证在saveMap实体和可选抛出一个异常
  // 2)在saveMap更新任何实体
  // 3)添加新实体的saveMap
  // 4)删除保存的地图实体。
  // 例如
  清单< EntityInfo> fooInfos;
  如果(!saveMap.TryGetValue(typeof运算(富),出fooEntities)){
     //修改或删除任何fooEntites的
     //或者添加新的entityInfo实例的fooEntities列表。
  }}

i am Trying to fit in breezeJS with my existing architecture. I have a structure like

  1. html/JS/Angular :: based view using hot-towel angular.
  2. web api controllers :: whom the view calls.
  3. Services layer :: that is being called from Web api. Any business logic goes here.
  4. Unit of Work :: And (if) business logic requires to talk to data base for CRUDs it calls UOW.
  5. Repository Pattern :: UOW is actually wrapping repositories. and repositores in turn talking to DbContexts.

Uptill now i was able to conver normal repositories implementation into the one using

public EFContextProvider<MyContext> DbContext { get; set; }

instead of just DbContext and i am also exposing MetaData using a string property with in UOW and IQueryables are returned using DbContext.Context.SomeEntity

Question 1 : Am i on right track ?? Question 2 : Most of the breeze examples are suggesting one SaveChanges method that give you all the entities that were changed and it will persist it at once. What if i want to trigger some business logic before Add,Update and Delete. i want to call me AddSomething service method and want to have a particular type of entity being sent to AddSomething and run some business logic before persistence. How can i put it together.

my code looksl ike

  [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);
    //}

Below is the service

 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();
    }
}

every service can expose one property through base. that is actually the meta data

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

and the my UOW looks like

    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
}

in the end Repository Implementaion looks like

   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);
    }
}

解决方案

Breeze supports "Named saves" where you specify the name of the specific server endpoint ( i.e. your service method) on a per save basis. See:

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

This would look something like this on your client.

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

}

and on your server

[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.
  }

}

这篇关于其中,doese微风适合的nTier架构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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