Ask AyendeHandling filtering
With regards to my quests against repositories, Matt asks:
…if my aggregate root query should exclude entities that have, for example, and IsActive = false flag, I also don't want to repeatedly exclude the IsActive = false entities. Using the repository pattern I can expose my Get method where internally it ALWAYS does this.
The problem with this question is that it make a false assumption, then go ahead and follow on that false assumption. The false assumption here is that the only way to handle the IsActive = false in by directly querying that. But that is wrong.
With NHibernate, you can define that with a where condition, or as a filter. With RavenDB, you can define that inside a query listener. You can absolutely set those things up as part of your infrastructure, and you won’t need to create any abstractions for that.
More posts in "Ask Ayende" series:
- (28 Feb 2012) Aggregates and repositories
- (31 Jan 2012) What about the QA env?
- (25 Jan 2012) Handling filtering
- (19 Jan 2012) Life without repositories, are they worth living?
- (17 Jan 2012) Repository for abstracting multiple data sources?
Comments
I've worked with systems that do that. It's a really great source of confusing NullReferenceExceptions when a record that is in the database doesn't get returned by an abstraction that doesn't in any way indicate that it does such filtering. It's also a hindrance when writing the code that has to deal with the inactive records as suddenly none of the common structure applies.
(The NullReferenceExceptions on records not being found is an entirely separate flaw)
I don't agree the assumption is flawed - your context is different.
The original comment was to do with a pattern of implementation, but the answer uses NHibernate to say that it's incorrect.
What if I'm not using NHibernate, and don't have filtering at my disposal, or anything like it?
Or even if I am using NHib, what if there are valid use cases for fetching everything with IsActive = false - the DEFAULT retrieval mechanism should filter these out but in some cases I want to see them? I don't want a global query override that prevents my data layer from returning the records.
Leaving it up to the developers to always exclude the relevant records is not a great idea on a large system, so I absolutely agree that having it as part of your infrastructure is 1st prize, but I'm not sold on the filtering suggestion being a valid alternative in all cases. Extension methods, as mentioned in a previous post, may work here too, but still aren't optimal in my opinion.
Just to elaborate on the previous comment, I'm using a trivial example to highlight the common need to filter out records without having developers implement WHERE statements all over the system.
When just IsActive = true is a requirement, that's no huge overhead, but what about (where IsVerified = true AND IsActive = true AND IsNotLockedOut = true)?
Matt, I gave several example of how you can modify that using different methods, NHibernate, RavenDB, etc. Most OR/M has some way to do those sort of things.
For the scenarios that you posit, NHibernate has support for filters, so it isn't a static decision, you can add/remove them.
Aren't filters globally applied though? In which case, filters don't work if you want to expose the reverse but force it to be explicitly used instead of as the default?
Don't get me wrong - I absolutely see your point that in most cases repositories are overkill in the NHibernate world, but I do disagree with the premise that there is no room for abstraction to another layer for certain applications.
I'm still not convinced there is an absolute for either approach, instead the best approach lies somewhere in the middle.
Matt, I never said that there isn't a need to abstract some things out. What I said was that there isn't a need to do that in the common case. In a typical app, you have cause to abstract 5% - 10% of the data access, because it is complicated / ugly.
The rest is trivial , and should be treated as such
We're arguing the same thing then - except we have differing views of what should be abstracted and what is not.
You argue this should NOT be abstracted:
http://ayende.com/blog/153153/northwind-starter-kit-review-refactoring-to-an-actual-read-model
I say it probably should. I guess it all boils down to a matter of opinion.
Funnily enough, this is something I've been wrestling with myself for some time now, so these posts are pertinent to me personally - thanks for the frequent posts and I hope they keep coming.
Ayende
How do you control caching data when exposing ISession/IDbContext directly to your controllers when for example your working within a team environment? each team member would not know that the other person is storing the data in cache unless scanning the files.
Marco, Caching is something that you do for a _specific scenario_, this isn't something that you do globally. Therefor, you don't care what someone else is doing
@Ayende,
I dont think EF Code First supports that kind of default filtering.
http://stackoverflow.com/questions/6932209/how-can-i-have-entity-framework-return-related-objects-with-some-defaults
@Matt
You can add something specificationesque to solve the problem at hand. Throw the isession/idbcontext in a getactiveroot class which adds the filter
@Ignacio Fuentes,
I wrote a post just for you, to describe how I handle this type of filtering in my EF infrastructure:
http://www.matthidinger.com/archive/2012/01/25/a-smarter-infrastructure-automatically-filtering-an-ef-4-1-dbset.aspx
"With RavenDB, you can define that inside a query listener." Link please?
@John
See the docs here http://old.ravendb.net/documentation/triggers/read
Ayendt I'm rewatching Hibernating Rhinos #9 and you do exactly what you now say is wrong. You show how to create repositories. And you do use ORM with those repositories. A lot changed in your practices I see.
Karep, Indeed, practices change over time, based on actual experience in the field and seeing what works and what doesn't work.
Thanks for response. Now it's clear. Sometimes seems that you contradict yourself but I should probably take into account that some posts are from long time ago.
Comment preview