I am trying to set up proper domain architecture using Fluent NHibernate and Linq to NHibernate. I have my controllers calling my Repository classes, which do the NHibernate thang under the hood and pass back ICollections of data. This seems to work well because it abstracts the data access and keeps the NHibernate functionality in the "fine print".
However, now I'm finding situations where my controllers need to use the same data calls in a different context. For example, my repo returns a list of Users. That's great when I want to display a list of users, but when I want to start utilizing the child classes to show roles, etc., I run into SELECT N+1 issues. I know how to change that in NHibernate so it uses joins instead, but my specific question is WHERE do I put this logic? I don't want every GetAllUsers() call to return the roles also, but I do want some of them to.
So here are my three options that I see:
Change the setting in my mapping so the roles are joined to my query.
Create two Repository calls - GetAllUsers() and GetUsersAndRoles().
Return my IQueryable object from the Repository to the Controller and use the NHibernate Expand method.
Sorry if I didn't explain this very well. I'm just jumping into DDD and a lot of this terminology is still new to me. Thanks!
As lomaxx points out, you need query.Expand.
To prevent your repository from becoming obscured with all kinds of methods for every possible situation, you could create Query Objects which make configurable queries.
I posted some examples using the ICriteria API on my blog. The ICriteria API has FetchMode instead of Expand, but the idea is the same.
I try and keep all the query logic in my repositories and try to only pass back the ICollection from them.
In your situation, I'd pass in some parameters to determine if you want to eager load roles or not and construct the IQueryable that way. For example:
GetAllUsers(bool loadRoles)
{
var query = session.Linq<Users>();
if(loadRoles)
query.Expand("Roles");
return query.ToList();
}
I would choose 2, creating two repositories. And perhaps would I consider creating another repository call to GetRoleByUser(User user). So, you could access a user's role upon user selection change on a seperate thread, if required, so it would increment your performance and won't load every user's roles for each of your users, which would require most resources.
It sounds like you are asking if it is possible to make GetAllUsers() sometimes return just the Users entities and sometimes return the Users and the roles.
I would either make a separate repository method called GetRolesForUser(User user), use lazy loading for Roles, or use the GetAllUsers(bool loadRoles) mentioned by lomaxx's answer.
I would lean toward lazy loading roles or a separate method in your repository.
Related
I am developing a website for a beauty salon. There is an admin part of the website, where the esthetician can add a new care. A care is linked to a care category (all cares related to hands, feets, massages, ...). To solve this I wrote this code into the CareRepository in the .NET API :
public async Task<Care?> AddAsync(Care care)
{
// var dbCareCategory = await this._careCategoryRepository.GetByNameAsync(care.CareCategoryName);
if (string.IsNullOrEmpty(care.CareCategoryName) || string.IsNullOrWhiteSpace(care.CareCategoryName))
return null;
var dbCareCategory = await this._instituteDbContext.CareCategories
.Where(careCategory => Equals(careCategory.Name, care.CareCategoryName))
.Include(careCategory => careCategory.Cares)
.FirstOrDefaultAsync();
if (dbCareCategory == null || dbCareCategory.Cares.Contains(care))
return null; // TODO : improve handling
dbCareCategory.Cares.Add(care);
await this._instituteDbContext.SaveChangesAsync();
return care;
}
My problem here is that I am a bit struggling with the best practice to have, because in order to add a care to a category, I have to get the category first. At the first place, I called the CareCategoryRepository to get the care (commented line). But then, EF was not tracking the change, so when I tried to add the care, it was not registered in the database. But once I call the category from the CareRepository, EF tracks the change and saves the Care in the database.
I assume this is because when calling from another repository, it is a different db context that tracks the changes of my entity. Please correct me if my assumption is wrong.
So, I am wondering, what is the best practice in this case ?
Keep doing what I am doing here, there is no issue to be calling the category entities from the care repository.
Change my solution and put the AddCare method into the CareCategoryRepository, because it makes more sense to call the categories entities from the CareCategoryRepository.
Something else ?
This solution works fine, however I feel like it may not be the best way to solve this.
The issue with passing entities around in web applications is that when your controller passes an entity to serve as a model for the view, this goes to the view engine on the server to consume and build the HTML for the view, but what comes back to the controller when a form is posted or an AJAX call is made is not an entity. It is a block of data cast to look like an entity.
A better way to think of it is that your Add method accepts a view model called AddCareViewModel which contains all of the fields and FKs needed to create a new Care entity. Think about the process you would use in that case. You would want to validate that the required fields are present, and that the FKs (CareCategory etc.) are valid, then construct a Care entity with that data. Accepting an "entity" from the client side of the request is trusting the client browser to construct a valid entity without any way to validate it. Never trust anything from the client.
Personally I use the repository pattern to serve as a factory for entities, though this could also be a separate class. I use the Repository since it already has access to everything needed. Factory methods offer a standard way of composing a new entity and ensuring that all required data is provided:
var care = _careRepository.Create(addCareViewModel.CareCategoryId,
/* all other required fields */);
care.OptionalField = addCareViewModel.OptionalField; // copy across optional data.
_context.SaveChanges(); // or ideally committed via a Unit of Work wrapper.
So for instance if a new Care requires a name, a category Id, and several other required fields, the Create method accepts those required fields and validates that they are provided. When it comes to FKs, the repository can load a reference to set the navigation property. (Also ensuring that a valid ID was given at the same time)
I don't recommend using a Generic Repository pattern with EF. (I.e. Repository()) Arguably the only reason to use a Repository pattern at all with EF would be to facilitate unit testing. Your code will be a lot simpler to understand/maintain, and almost certainly perform faster without a Repository. The DbContext already serves all of those needs and as a Unit of Work. When using a Repository to serve as a point of abstraction for enabling unit testing, instead of Generic, or per-entity repositories, I would suggest defining repositories like you would a Controller, with effectively a one-to-one responsibility.
If I have a CareController then I'd have a CareRepository that served all needs of the CareController. (Not just Care entities) The alternative is that the CareController would need several repository references, and each Repository would now potentially serve several controllers meaning it would have several reasons to change. Scoping a repository to serve the needs of a controller gives it only one reason to change. Sure, several repositories would potentially have methods to retrieve the same entity, but only one repository/controller should be typically responsible for creating/updating entities. (Plus repositories can always reference one another if you really want to see something as simple as Read methods implemented only once)
If using multiple repositories, the next thing to check is to ensure that the DbContext instance used is always scoped to the Web Request, and not something like Transient.
For instance if I have a CareRepository with a Create method that calls a CareCategoryRepository to get a CareCategory reference:
public Care Create(string name, int careCategoryId)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameOf(name));
var care = new Care { Name = name };
var careCategory = _careCategoryRepository.GetById(careCategoryId);
care.CareCategory = careCategory;
_context.Cares.Add(care);
}
We would want to ensure that the DbContext reference (_context) in all of our repositories, and our controller/UnitOfWork if the controller is going to signal the commit with SaveChanges, are pointing at the exact same single reference. This applies whether repositories call each other or a controller fetches data from multiple repositories.
I developed a few cakephp3 apps, and now I'm learning how to use cakephp4. I'm trying to centralize all my authorization logic in the *Policy classes. I have a situation where a user wants to access a entity/index page, and I want to validate if he can access this index page by doing some queries.
So right now I'm using $this->Authorization->authorize($this->Entity->newEmptyEntity()); in the controller, in order to be able to access an EntityPolicy->canIndex() method. Is there a more elegant way to do it, to call a policy method without an instance of the entity?
After that, in order to be able to run my queries, I'm using the ModelAwareTrait in the class, and querying data in a similar way that I do in controllers. Is there a better approach?
Send the entity itself. For example, if you are using the Articles controller
$this->Authorization->authorize($this->Articles);
$this->Authorization->can($this->Articles,'index')
While declaring the canIndex() method normally in your Policy.
My solution was somewhat different (and easier I guess)
//In my ProjectController.php
public function index()
{
$project = new Project();
$this->Authorization->authorize($project);
}
this way I don't have to do a useless query (I just create an empty Project object), but at the same time I can check the user attributes.
In my case the solution proposed by #eos (above) didn't work, because calling
$this->Authorization->authorize($this->Projects);
lead to an unwanted result.
I have created a little project where I pass data from my controllers to a service class which uses an ORM to for example save an object:
Something like this:
The UserController receives the post data and passes it to the UserService.
The UserService creates a user object and saves it to the database with $user.save();
Now I'm struggling with two things:
First:
Let's say I use a repository to add the user, it would be like this:
Controller passes post data to the service which creates the user object and passes it to the repository. The only thing the repository has to do is call $user.save(), isn't that a bit weird? Why not calling save in my service, because using a repository just to call a save method seems overkill to me.
Second:
I read that when you use repositories, you can easily change storage methods because your application isn't aware which one is used. But before passing an object to your repository, you have to create it.
Using an ORM, each one has a different way: Doctrine uses $user = new User while Propel uses $user = new User(), idiorm uses $user = ORM::for_table('user')->create(); So when switching to another ORM for some reason comes with changing this in your project too, no?
First: Have a read about the responsibilities of Model View and Controller. There's a reasonable explanation with an example at this site: http://tomdalling.com/blog/software-design/model-view-controller-explained/
With regard to the Model and your ORM - the ORM would probably exist within the Model. So you should be asking your Model to create a new object (which may represent a single table or a series of related tables - your Model should understand these relationships). You can then pass data to your Model and your Model should then store the data into the appropriate columns in the appropriate tables. A simple example, imagine creating an object called 'Family' where you might specify 2 parent names, a variable number of children names and then tell the Model to save this. The Model may take this 'Family' object and create a single Family table record and 5 Person table records, flagging some as parents and others as children.
Second: The 'Storage Methods' referred to are (in my opinion) referring to the database you use. For example I know that Propel supports MySQL, PostgreSql, MSQL, Oracle, and others. My switch the configuration to a different database Propel will automatically start talking the appropriate language for the new database.
It appears that all the existing breezejs examples are passing entity models to and from the BreezeController.
But almost all our pages built are using some form of view models. In the days we have no BreezeJs, we retrieve the data (domain model) from a repository to populate (using AutoMapper or manually) a view model, which contains only the necessary data for that view. The WebAPI sends only the view model data over to the browser where we can populate a client-side view model (usually a knockout observable).
When saving data, we collect data from a <form> to populate an input view model, send only that data over to the server, where data in the input view model is mapped to the domain model. The update is saved by calling SaveChanges() on the DbContext entity in the repository.
Now, BreezeJs is to take over all our repository code by creating an EFContextProvider. The examples I have seen usually retrieve the domain model data and then pass it all to the client side.
[HttpGet]
public IQueryable<Item> Items() {
return _contextProvider.Context.Items;
}
It is the client-side javascript's job to build a view model.
Of course it is possible for us to build the view model at the server side:
[HttpGet]
public List<ItemViewModel> Items() {
var items = _contextProvider.Context.Items
.Include("RelatedEntity")
.ToList();
var model = new List<ItemViewModel>();
.... some code to build model from items ....
return model;
}
The benefit is that less data is transferred across the network, and we can do many manipulations on the server side. But I don't know if it is a good practice to modify this BreezeController like that. But at least, it returns data needed to list all the items.
The real trouble came when I tried to POST data back.
In the BreezeJs examples I found, they use a ko.observableArray() to store all the domain model data, let's say vm.items. Then the new record newItem is build by manager.createEntity into a domain model. After validating the data, item.entityAspect.validateEntity(), the newItem is pushed into vm.items and manager.saveChanges() is called, which somehow invokes SaveChanges() on the BreezeController.
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle) {
return _contextProvider.SaveChanges(saveBundle);
}
I find too many things have been taken over! (Laugh at me if you disagree.) My questions are:
Can I just createEntity and then saveChanges?
I only have an empty form to fill in and submit. There is certainly no need to build a whole items array on the client-side.
Can I pass an input view model as a JObject and do some server-side processing before calling _contextProvider.SaveChanges()?
It turns out to be a super long post again. Thank you for reading it all through. Really appreciate it!
Good questions. Unfortunately, our demo code seems to have obscured the real capabilities of Breeze on both client and server. Breeze is not constrained in the ways that your fear.
I don't want to repeat everything that is in our documentation. We really do talk about these issues. We need more examples to be sure.
You are describing a CQRS design. I think it over-complicates most applications. But it's your prerogative.
If you want to send ItemViewModel instead of Item, you can. If you want that to be treated as an entity on the Breeze client - have the EntityManager turn it into a KO observable and manage it in cache, change track it, validate it -, you'll have to provide metadata for it ... either on server or client. That's true for Breeze ... and every other system you can name (Ember, Backbone, etc). Soon we will make it easier to create metadata on the server for an arbitrary CLR model; that may help.
You have complete control over the query on the server, btw, whether Item or ItemViewModel. You don't have to expose an open-ended query for either. You seem to know that by virtue of your 2nd example query.
On to the Command side.
You wrote: "[the examples] use a ko.observableArray() to store all the domain model data, let's say vm.items"
That is not precisely true. The items array that you see in examples exists for presentation. The items array isn't storing anything from a Breeze perspective. In fact, after a query, the entities returned in the query response (if they are entities) are already in the manager's cache no matter what you do with the query result, whether you put them in an array or throw them away. An array plays no role whatsoever in the manager's tracking of the entities.
You wrote: "Can I just createEntity and then saveChanges?"
Of course! The EntityManager.createEntity method puts a new entity in cache. Again, the reason you see it being pushed into the items array is for presentation to the user. That array has no bearing on what the manager will save.
You wrote: "Can I pass an input view model ... and do some server-side processing before calling _contextProvider.SaveChanges()?"
I don't know what you mean by "an input viewmodel". The Breeze EntityManager tracks entities. If your "input viewmodel" is an entity, the EntityManager will track it. If it has changed and you call saveChanges, the manager will send it to the controller's SaveChanges method.
You own the implementation of the controller's SaveChanges method. You can do anything you want with that JObject which is simply a JSON.NET representation of the change-set data. I think you'll benefit from the work that the ContextProvider does to parse that object into a SaveMap. Read the topic on Customizing the EFContextProvider. Most people feel this provides what they need for validating and manipulating the client change-set data before passing those data onto the data access layer ... whether that is EF or something else.
If instead you want to create your own, custom DTO to POST to your own custom controller method ... go right ahead. Don't call EntityManager.saveChanges though. Call EntityManager.getChanges() and manipulate that change array of entities into your DTO. You'll be doing everything by hand. But you can. Personally, I'd have better things to do.
Had a question about what best practice might be for the implementation of "convenience" queries. In reference to this article:
http://www.jasongrimes.org/2012/01/using-doctrine-2-in-zend-framework-2/#toc-install-doctrine-modules
It's clear that the entity manager is available in the IndexController - he does a findAll to list the entire contents of the database. What if, however, we added a "band" column to the database, mapped it out, and wanted to query all albums by the Beatles? What if the Beatles albums were used rather often throughout the codebase (weak example, but you get it).
The EM only seems to be available in Controllers, and Classes don't really seem to be aware of the service locator.
Would you simply break out DQL right in the controller, and repeat the DQL in every controller that needs it? (not very DRY)
Do we instead finagle some access to the EM from the Entity, or Model?
Doesn't seem as cut-and-dry as straight Zend_Db usage where you can fire queries anywhere you like, cheating to get things done.
Thanks for helping me cross over into a "real" ORM from the Table Gateway world.
Erm, Doctrine 2 is able to handle Relationships (e.g.: Bands to Albums and vice-versa)
The EntityManager can be made available in every single class you wish, as long as you define the class as a service. I.e. inside your Module.php you can define a factory like this:
// Implement \Zend\ModuleManager\Feature\ServiceProviderInterface
public function getServiceConfig() {
return array(
//default stuff
'factories' array(
'my-album-service' = function($sm) {
$service = new \My\Service\Album();
$service->setEntityManager($sm->get('doctrine.entitymanager.orm_default'));
return $service;
}
)
)
);
You can then call this class from every Class that is aware of the ServiceManager like $this->getServiceLocator()->get('my-album-service')
This class would then automatically be injected with the Doctrine EntityManager.
To be clear: All queries you'd do SHOULD be located inside your Services. You'd have your Entities, which are basically the DB_Mapper from Doctrine 2, then you have your Services, which run actions like add(), edit(), findAll(), findCustomQuery(), etc...
You would then populate your Services with Data from the Controllers, the Service would give data back to the controller and the controller would pass said data to the view. Does that make sense to u and answer your question?