Ayende @ Rahien

Refunds available at head office

Ask Ayende: Handling 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.

Tags:

Posted By: Ayende Rahien

Published at

Originally posted at

Comments

Colin Scott
01/25/2012 10:40 AM by
Colin Scott

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)

Matt
01/25/2012 11:28 AM by
Matt

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.

Matt
01/25/2012 11:32 AM by
Matt

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)?

Ayende Rahien
01/25/2012 11:45 AM by
Ayende Rahien

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.

Matt
01/25/2012 11:58 AM by
Matt

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.

Ayende Rahien
01/25/2012 12:07 PM by
Ayende Rahien

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

Matt
01/25/2012 12:21 PM by
Matt

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.

Marco
01/25/2012 01:01 PM by
Marco

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.

Ayende Rahien
01/25/2012 02:08 PM by
Ayende Rahien

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

Ignacio Fuentes
01/25/2012 05:09 PM by
Ignacio Fuentes

@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

Benny Michielsen
01/25/2012 06:14 PM by
Benny Michielsen

@Matt

You can add something specificationesque to solve the problem at hand. Throw the isession/idbcontext in a getactiveroot class which adds the filter

Matt Hidinger
01/25/2012 08:11 PM by
Matt Hidinger

@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

John
01/25/2012 09:25 PM by
John

"With RavenDB, you can define that inside a query listener." Link please?

Matt Warren
01/27/2012 12:21 PM by
Matt Warren

@John

See the docs here http://old.ravendb.net/documentation/triggers/read

Karep
01/28/2012 12:36 PM by
Karep

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.

Ayende Rahien
01/29/2012 11:22 AM by
Ayende Rahien

Karep, Indeed, practices change over time, based on actual experience in the field and seeing what works and what doesn't work.

Karep
02/02/2012 10:00 PM by
Karep

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.

Comments have been closed on this topic.