其中,doese微风适合的nTier架构 [英] where doese breeze fits into ntier architecture
问题描述
我想以适应breezeJS与我现有的架构。我有一个像
的结构- HTML / JS /角::基于使用热毛巾角视图。
- 网页API控制器::人的观点电话。
- 服务层::正从网页API调用。任何业务逻辑放在这里。
- 工作单位::和(If)的业务逻辑,需要倾诉的数据基础调用UOW CRUDs。
- 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
- html/JS/Angular :: based view using hot-towel angular.
- web api controllers :: whom the view calls.
- Services layer :: that is being called from Web api. Any business logic goes here.
- Unit of Work :: And (if) business logic requires to talk to data base for CRUDs it calls UOW.
- 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屋!