New Posts New Posts RSS Feed: Why doesnt StaffingResourceSearchRepository use the base repository
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Why doesnt StaffingResourceSearchRepository use the base repository

 Post Reply Post Reply
Author
JohnBloom View Drop Down
Groupie
Groupie
Avatar

Joined: 30-Nov-2010
Location: Topeka, KS
Posts: 95
Post Options Post Options   Quote JohnBloom Quote  Post ReplyReply Direct Link To This Post Topic: Why doesnt StaffingResourceSearchRepository use the base repository
    Posted: 13-Jun-2012 at 2:06pm
We have lots of search repositories and I was about to try and move them into my main repositories when I saw that temphire had a seperate repository for its search logic. Why didnt you just put FindStaffingResourcesAsync in the StaffingResourceRepository? It would have saved you from having to type these lines of code:

private readonly IEntityManagerProvider<TempHireEntities> _entityManagerProvider;
 
 [ImportingConstructor]
 public StaffingResourceSearchRepository(IEntityManagerProvider<TempHireEntities> entityManagerProvider)
 {
     _entityManagerProvider = entityManagerProvider;
 }
 
 private TempHireEntities EntityManager
 {
     get { return _entityManagerProvider.Manager; }
 }
-John Bloom
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 13-Jun-2012 at 3:04pm
The main reason was because the search doesn't return entities. It returns StaffingResourceListItem POCOs as the result of a projection query optimized for the search result. At the time it felt better to seperate them into different repositories as not to confuse the FindAsync method with FindStaffingResourceAsync. Additionally, one may potentially use differently shaped POCOs for searching StaffingResources in other modules, so there may in fact be multiple search repositories for the same underlying entity, each one returns a POCO optimized for what the particular module actually displays in it's search results.
 
I'm not feeling very strongly about this approach. I could also see Search methods being added to the StaffingResourceRepository. Now that I'm thinking about it again, I'm actually tempted to create an overload for FindAsync, that allows you to perform a projection. The signature would look something like this:
 
OperationResult<IEnumerable<TResult>> FindAsync<TResult>(Func<IQueryable<T>, IQueryable<TResult>> selector,
                                                  Expression<Func<T, bool>> predicate = null,
                                                  Func<IQueryable<TResult>, IOrderedQueryable<TResult>> orderBy = null,
                                                  Action<IEnumerable<TResult>> onSuccess = null,
                                                  Action<Exception> onFail = null);
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 13-Jun-2012 at 9:09pm
John,
I followed through with my idea and added a number of FindAsync overloads to CocktailContrib 1.0.7, that allow you to do strongly-typed and dynamic projection queries. It's all pushed to NuGet and I pushed an updated version of TempHire to CodePlex demonstrating how to use it. 
Back to Top
JohnBloom View Drop Down
Groupie
Groupie
Avatar

Joined: 30-Nov-2010
Location: Topeka, KS
Posts: 95
Post Options Post Options   Quote JohnBloom Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2012 at 7:22am
I am not sure if I like this that much. We have always pushed to keep query logic in repositories and out of the view models. I understand that the manager is still hidden in the repository but thats about it with this query. The rest of the it is in the vm. That seems to go against what you have previously presented to us as a clean vm (ie no business logic in vm only function calls).

I also understand what you are doing and I think it may work in a sample but we have been saying the similar things as,  "one may potentially use differently shaped POCOs for searching StaffingResources in other modules." That causes us to decouple our code only to realize that it is a lot of work to re-implement searching again and in many cases we will never get around to it or we want it to be the same. 

This can become somewhat of a maintenance issue as you put so many hooks into your application for extensiblility for the future but dont end up using them. For searching we ended up using a SearchListItem and making all of our searches conform to that. Less extensible yes but sometimes you aint going to need it.
-John Bloom
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2012 at 8:10am
Actually, what's being done here in the view model is data transformation, filtering and sorting. Three things view models do all the time. The view models job is to map the business data to the UI and back. That's exactly what's happening here. The business data is shaped for the search result grid.

I agree that it might be a little bit too much metal visible in the view model, but that's easily rectified. We may have just found the use case for a domain service example for TempHire. You can move this code into a search service on the UoW, that has the simple signature that you are looking for and then internally uses the FindAsync method of the repository to perform the projection query.
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2012 at 11:08am
John,
I've updated TempHire on CodePlex and moved the search logic to a search service. I must admit, search in TempHire was a bit of an afterthought, so I appreciate you poking holes. In this simple case I thought of it as just another way to fetch the data, but it's really not. Search involves business logic and as such doesn't belong in the repository. The repository's job is to fetch data and return it in the shape you requested it. Any logic around the data belongs as previously established in a domain service.

So, in your case you can keep the search service interface pretty standard as always returning SearchListItems, but then the actual implementation is different depending on what you search for. The new repository methods should allow you to project into SearchListItem under the hood, by simply supplying the correct selector based on the underlying entity.
Back to Top
JohnBloom View Drop Down
Groupie
Groupie
Avatar

Joined: 30-Nov-2010
Location: Topeka, KS
Posts: 95
Post Options Post Options   Quote JohnBloom Quote  Post ReplyReply Direct Link To This Post Posted: 14-Jun-2012 at 11:25am
Searching is a big deal in our application. I am glad that there is actually searching in TempHire. A lot of sample applications ignore that aspect since they usually deal with a small set of clean test data. When dealing with real data you find out that there can be 15 different John Smiths and you need to be able to get to the right one. 

I think our search is pretty close to what you are describing. We are probably doing more work per class than we have to because doing projection under that hood is something that we have been struggling with. 
-John Bloom
Back to Top
jkattestaart View Drop Down
Newbie
Newbie


Joined: 30-Jul-2010
Location: Netherlands
Posts: 37
Post Options Post Options   Quote jkattestaart Quote  Post ReplyReply Direct Link To This Post Posted: 23-Jun-2012 at 9:22am
Hi,
 
In the old version i used a separate Enitimanager call get some related data when i creata the listitem (the entity is not there because of a complex relation). However this is no longer possible. Should i use the old concept to get this data or is there a more elegant way. This is the expression i used
 

new PersonListItem{ Id = x.Id, 

   ..... etc
 
Gender = EntityManager.SystemCodes......
 
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 23-Jun-2012 at 9:57am
In the old version, search was done through its own repository, which naturally used an EntityManager directly. Now, search is a service that uses a repository under the hood. Services should never directly use an EntityManager. Data access should always be performed through a repository as that gives you one place to optimize your queries. For example in TempHire some of the repositories return pre-cached data instead of going back to the database, but the callers to the repository never know and don't need to know. If your data access is spread all over it gets much harder to optimize.
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 23-Jun-2012 at 10:01am
Reading your question again. I'm trying to understand what you are asking. A service can use multiple repositories if it needs to retrieve related data. The latest generic repository implementation now also allows you to do projections so you can pull in related data through navigation properties.
Back to Top
jkattestaart View Drop Down
Newbie
Newbie


Joined: 30-Jul-2010
Location: Netherlands
Posts: 37
Post Options Post Options   Quote jkattestaart Quote  Post ReplyReply Direct Link To This Post Posted: 23-Jun-2012 at 10:18am
Thx for your quick reply. I don't have a navigation property here (due to the lack of a proper foreign key)
So i guess i have to use a enititymanager again to get my data.
In the old version this was instantiated by MEF but now i only have a repository.
Should i instantiate the repository of that entity to get the data?
 
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 23-Jun-2012 at 10:40am
Correct. You should have a UoW that is instantiated by MEF. The UoW then instantiates all the necessary repositories and services, passing the appropriate repositories to the constructor of the services. So yes you would have your UoW instantiate the repository for the entity in question and pass it to the service, so that the service can retrieve the related data. Btw, you can always create navigation properties in the model without having an actual foreign key relationship in the DB.
Back to Top
jkattestaart View Drop Down
Newbie
Newbie


Joined: 30-Jul-2010
Location: Netherlands
Posts: 37
Post Options Post Options   Quote jkattestaart Quote  Post ReplyReply Direct Link To This Post Posted: 23-Jun-2012 at 10:43am
OK, thx for the answer.
I do use navigation properties for the normal foreign keys but only in this situation this does not apply.
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down