Using this:
https://genericunitofworkandrepositories.codeplex.com/
and the following set of blog posts:
We are trying to use those repositories with Breeze
since it handles client side javascript and OData very well.
I was wondering how we could use these with Breeze
to handle overriding the BeforeSaveEntity
correctly.
We have quite a bit of business logic that needs to happen during the save (modifying properties like ModifiedBy
, ModifiedTime
, CreatedBy
, etc) but when we change those they aren't updated by breeze, so we have to re query after the save (we've tried manually mapping the changes back but it requires us to duplicate all of the business logic).
Our second option was to check the type of each entity
and then request the correct repository for it, handle the save internally, and then do a new get request on the client to get the updated information. This is chatty though so we were hoping there is a better way. What would the correct way of updating these objects while bypassing breeze's save without returning an error or having to reget the data afterward?
Any examples of Breeze with Business Logic during the save would be very helpful, especially if it happens in a service, repository or something else besides directly in the BeforeSaveEntity
method.
This is many questions rolled into one and each is a big topic. The best I can do is point you in some directions.
Before I get rolling, let me explain why you're not seeing the effects of setting "properties like
ModifiedBy
,ModifiedTime
,CreatedBy
, etc)". TheEFContextProvider
does not update every property of the modified entities but rather only those properties mentioned in theEntityInfo.OriginalValuesMap
, a dictionary of the property names and original values of just the properties that have changed. If you want to save a property that is only set on the server, just add it to the original values map:Now Breeze knows to save these properties as well and their new values will be returned to the client.
Let's return to the bigger picture.
Breeze is first and foremost an client-side JavaScript library. You can do pretty much whatever you want on the server-side and make Breeze happy about it as long as your server speaks HTTP and JSON.
Writing a server that provides all the capabilities you need is not trivial no matter what technology you favor. The authors of Breeze offer some .NET components out of the box to make your job easier, especially when you choose the Web API, EF and SQL Server stacks.
Our .NET demos typically throw everything into one web application. That's not how we roll in practice. In real life we would never instantiate a Breeze
EFContextProvider
in our Web API controller. That controller (or multiple controllers) would delegate to an external class that is responsible for business logic and data access, perhaps a repository or unit-of-work (UoW) class.Repository pattern with Breeze .NET components
We tend to create separate projects for the model (POCOs usually), data access (ORM) and web (Web API plus client assets) projects. You'll see this kind of separation in the DocCode Sample and also in John Papa's Code Camper sample, the companion to his PluralsSight course "Building Apps with Angular and Breeze".
Those samples also demonstrate an implementation of the repository pattern that blends the responsibilities of multiple repositories and UoW in one class. This makes sense for the small models in these samples. There is nothing to stop you from refactoring the repositories into separate classes.
We keep our repository class in the same project as the EF data access material as we see no particular value in creating yet another project for this small purpose. It's not difficult to refactor into a separate project if you're determined to do so.
Both the Breeze and Code Camper samples concentrate on Breeze client development. They are thin on server-side logic. That said, you will find valuable clues for applying custom business logic in the
BeforeSaveEntities
extension point in the "NorthwindRepository.cs" and `NorthwindEntitySaveGuard.cs" files in the DocCode sample. You'll see how to restrict saves to certain types and certain records of those types based on the user who is making the request.The logic can be overwhelming if you try to channel all save changes requests through a single endpoint. You don't have to do that. You could have several save endpoints, each dedicated to a particular business operation that is limited to insert/updating/deleting entities of just a few types in a highly specific manner. You can be as granular as you please. See "Named Saves" in the "Saving Entities" topic.
Have it your way
Now there are a gazillion ways to implement repository and UoW patterns.
You could go the way set forth by the post you cited. In that case, you don't need the Breeze .NET components. It's pretty trivial to wire up your Web API query methods (
IQueryable
or not) to repository methods that returnIQueryable
(or just objects). The Web API doesn't have to know if you've got a BreezeEFContextProvider
behind the scenes or something completely different.Handling the Breeze client's
SaveChanges
request is a bit trickier. Maybe you can derive fromContextProvider
orEFContextProvider
; maybe not. Study the "ContextProvider.cs" documentation and the source code, especially theSaveChanges
method, and you'll see what you need to do to keep Breeze client happy and interface with however you want to handle change-set saves with your UoW.Assuming you change nothing on the client-side (that's an assumption, not a given ... you can change the save protocol if you want), your
SaveChanges
needs to do only two things:SaveResult
The
saveBundle
is a JSON package that you probably don't want to unpack yourself. Fortunately, you can derive a class fromContextProvider
that you use simply to turn thesaveBundle
into a "SaveMap", a dictionary ofEntityInfo
objects that's pretty much what anyone would want to work with when analyzing a change-set for validation and save.The following might do the trick:
Then it's up to you how you make use of the "SaveMap" and dispatch to your business logic.
The
SaveResult
is a simple structure:Use these classes as is or construct your own. Breeze client cares about the JSON, not these types.