Last active
January 2, 2016 11:59
-
-
Save CallumVass/8300400 to your computer and use it in GitHub Desktop.
Hacky way to load the correct service for before/after save operations to provide additional validation / business logic to entities for Breeze JS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SalesAppContextProvider : EFContextProvider<SalesAppContext> | |
{ | |
private readonly ServiceFactory _serviceFactory; | |
public SalesAppContextProvider(ServiceFactory serviceFactory) | |
{ | |
_serviceFactory = serviceFactory; | |
} | |
protected override bool BeforeSaveEntity(EntityInfo entityInfo) | |
{ | |
var entityType = entityInfo.Entity.GetType(); | |
var service = _serviceFactory.GetServiceFor(entityType); | |
switch (entityInfo.EntityState) | |
{ | |
case EntityState.Added: | |
return service.BeforeSaveEntityAdded(entityInfo.Entity); | |
case EntityState.Modified: | |
return service.BeforeSaveEntityModified(entityInfo.Entity); | |
case EntityState.Deleted: | |
return service.BeforeSaveEntityDeleted(entityInfo.Entity); | |
default: | |
return true; | |
} | |
} | |
protected override void AfterSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap, List<KeyMapping> keyMappings) | |
{ | |
foreach (var map in saveMap) | |
{ | |
var entityType = map.Key; | |
var service = _serviceFactory.GetServiceFor(entityType); | |
foreach (var entityInfo in map.Value) | |
{ | |
switch (entityInfo.EntityState) | |
{ | |
case EntityState.Added: | |
service.AfterSaveEntityAdded(entityInfo.Entity); | |
break; | |
case EntityState.Modified: | |
service.AfterSaveEntityModified(entityInfo.Entity); | |
break; | |
case EntityState.Deleted: | |
service.AfterSaveEntityDeleted(entityInfo.Entity); | |
break; | |
} | |
} | |
} | |
base.AfterSaveEntities(saveMap, keyMappings); | |
} | |
} | |
public class CustomerService : IService | |
{ | |
private readonly IMailService _mailService; | |
public CustomerService(IMailServce mailService) { | |
_mailService = mailService; | |
} | |
public bool BeforeSaveEntityAdded(object entity) | |
{ | |
return true; | |
} | |
public bool BeforeSaveEntityModified(object entity) | |
{ | |
return true; | |
} | |
public bool BeforeSaveEntityDeleted(object entity) | |
{ | |
return true; | |
} | |
public void AfterSaveEntityAdded(object entity) | |
{ | |
var customer = entity as Customer; | |
_mailService.NewCustomerNotification(customer); | |
} | |
public void AfterSaveEntityModified(object entity) | |
{ | |
} | |
public void AfterSaveEntityDeleted(object entity) | |
{ | |
} | |
} | |
public class ServiceFactory | |
{ | |
private readonly IMailService _mailService; | |
public ServiceFactory(IMailService mailService) { | |
_mailService = mailService; | |
} | |
private readonly Dictionary<Type, int> _typeDictionary = new Dictionary<Type, int> | |
{ | |
{ typeof(Collection), 0 }, | |
{ typeof(Customer), 1 } | |
}; | |
public IService GetServiceFor(Type entityType) | |
{ | |
switch (_typeDictionary[entityType]) | |
{ | |
case 0: | |
return new CollectionService(); | |
case 1: | |
return new CustomerService(_mailService); | |
default: | |
throw new ArgumentException("entityType"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yes, for sure you'd inject rather than new up the factory. You could get fancy and use MEF to have type-specific services self-register. But you're doing the most important thing which is factoring the business logic so that it isn't all lumped in a gigantic before/after interceptor and your factoring is both rational and flexible.
I've done such factoring myself in DocCode but I like your approach better and will probably steal it in a future DocCode update (I'll credit you and this gist).