RavenDb and the Repository Pattern

1,281 views
Skip to first unread message

Justin A

unread,
May 21, 2011, 2:24:46 AM5/21/11
to ravendb
Hi folks,

are any/many people using the Repository Pattern with RavenDb? As I
start learning RavenDb, my first reaction was to do this. And it works
fine. But I keep feeling that my Repository Pattern wrapper is just a
waste. Now -> i'm trying to be vary careful here because i don't want
to start a debate about the use of patterns and interfaces to remove
dependencies, help with mocking / testing / tight coupling, etc. ~~
This is not what I'm asking about ~~

I'm just curious if people are using it with RavenDb, for whatever
reason(s) :)

If you are, can u say why?
If not, can u also say why :)

I'm really really curious.

-Justin-

A-Dubb

unread,
May 21, 2011, 9:59:05 AM5/21/11
to ravendb

Itamar Syn-Hershko

unread,
May 21, 2011, 1:50:55 PM5/21/11
to rav...@googlegroups.com
Justin, why would you want to implement the repository pattern? what other storage solution would you want to be portable to? You can't do this efficiently to support RDBMSes, and if you want to support other doc dbs you are probably going to lose many RavenDB specific features, as well as other features the other dbs might have.

Tobi

unread,
May 21, 2011, 2:33:51 PM5/21/11
to rav...@googlegroups.com
On 21.05.2011 08:24, Justin A wrote:

> I'm just curious if people are using it with RavenDb, for whatever
> reason(s) :)

The app I'm using RavenDB with used NHibernate before and had several
IRepositories. Switching to RavenDB was more or less just changing the
IRepository implementations.

Since then, I've more and more dropped some of the IRepository
implementations. What's still left are repositories with methods more
complex than just running a single Linq/Lucene query or queries that are
used very often in different places of the app and giving them a dedicated
name makes the whole story more readable.

But the typical load/add/save stuff of the repositories is gone and I'm
using the session directly instead.

Tobias

Ayende Rahien

unread,
May 22, 2011, 4:03:22 AM5/22/11
to rav...@googlegroups.com

Dody Gunawinata

unread,
May 22, 2011, 4:23:13 AM5/22/11
to rav...@googlegroups.com
public interface IDocumentStorage<T>
{
Result<T> Save(T S);
IQuerySetOne<T> GetById(IKey key, string[] includePaths =
null, Action<ILoaderWithInclude<object>, T> loader = null);
IQuerySetOne<T> GetSingleByFilter(Expression<Func<T, bool>>
filter, bool force = false);
IQuerySetPaging<T> All<G>(Expression<Func<T, bool>> filter,
Expression<Func<T, G>> sortBy, int pageSize = 20, int currentPage = 1,
bool force = false, OrderOperator order = OrderOperator.Ascending);
Result<None> Delete(IKey key);
}

I have one generic implementation for IDocumentStorage and rely on
Autofac to handle the rest of the wiring. So if I need the persistence
service, I injected them thru constructor

public MyObjectConstructor(IDocumentStorage<Blog> blogStorage)
{
blogStorage.Load(xxx);
}

I am working on a web application and majority of the persistence call
are through this IDocumenStorage interface. Anything more complicated
gets its own class.

--
nomadlife.org

Tobi

unread,
May 22, 2011, 5:54:21 PM5/22/11
to rav...@googlegroups.com
On 22.05.2011 10:03, Ayende Rahien wrote:

> I tend to like to move those types of method to an extension method, like
> those:

I haven't considered this yet. It might be a matter of taste, but I
wouldn't feel comfortable with adding application specific code to the
RaveDB session.

Tobias

Justin A

unread,
May 24, 2011, 8:33:16 AM5/24/11
to ravendb
@A-Dubb : Cheers for the link, but I wasn't really asking about how to
do it (i've got some version working). It's interesting seeing how
others implement it thought.

@Itamar Syn-Hershko
"why would you want to implement the repository pattern?"
Yep - that's exactly the reason for this post. I've been using the
Repo Pattern with my projects for the last few years and wanted to see
what others thought about it with regards to RaveDb. The reason for my
curiosity was mainly when I was reading the Raven Docs and how they
mention that the UoW is built into the RavenDb architecture .. and was
re-enforced when I created my RavenDb implimentation of the my
IRepository<T> .. which turned out to be a very very very thin
wrapper. Then (i'm pretty sure) Ayende has a recent post about being
careful about over-engineering for the sake of doing that...

"what other storage solution would you want to be portable to?"
mock's (moq'ing the repository for unit tests).

@Ayende
" to an extension method"
Now that is interesting ...

@Dody - that's just a custom version of an IRepository<T> (but u've
called it an IDocStore). Similar to most repo implimentations which is
nice to see. For myself, I have services which can only call the
repositories. But i'm thinking of changing this now to make it so that
there's no Repository layer .. cause the DocSession is looking more
and more like this.

---

If I drop the repository layer, I'm just not sure how I can mock
things out in my unit tests? I'm guessing some people might suggest,
don't mock .. use the embedded store with some seeded data .. but I
still feel that this might be a bit too heavy (or not pure / true to
theory?).

thoughts?

Louis Haußknecht

unread,
May 24, 2011, 10:05:25 AM5/24/11
to rav...@googlegroups.com
Justin,

the recommended way of doing automated test is 
var store = new DocumentStore { RunInMemory = true; }

Cheers,

Louis

2011/5/24 Justin A <jus...@adler.com.au>

Dody Gunawinata

unread,
May 25, 2011, 4:43:07 AM5/25/11
to rav...@googlegroups.com
I think the topic of persistence techniques is a non issue since there
is no mapping layer and majority of the works are done in POCO
objects.

--
nomadlife.org

Justin A

unread,
May 26, 2011, 8:13:19 AM5/26/11
to ravendb
Thanks everyone :)

Much appreciated :)

Itamar Syn-Hershko

unread,
Feb 23, 2012, 6:04:34 PM2/23/12
to rav...@googlegroups.com
Just came around this, and it seems to sum it all up quite nicely, thought I'd post it here for future reference:

jalchr

unread,
Feb 24, 2012, 3:29:00 AM2/24/12
to rav...@googlegroups.com
Justin,
If your application is simple (a website UI only) then you can get away with not using the repository.

but I you plan to access your data/application from a console app in addition to the website, or more complex structure(like a distributed app with messaging and so) , than it would be better to dis-connect the structure and use the repository pattern or some custom form of it.

In all cases, I use it and the "extra" abstractions helped me scale my project structure without problems.

Oren Eini (Ayende Rahien)

unread,
Feb 24, 2012, 4:08:41 AM2/24/12
to rav...@googlegroups.com
Jalchr,
I would strongly disagree with you here. 
The needs of a console app or a backend processing app are drastically different than a web app.
Trying to have the same API for all of those scenarios hurts you, because you have to make compromises.

mare

unread,
Mar 29, 2013, 7:46:59 AM3/29/13
to rav...@googlegroups.com
The needs most often are very similar, serving Content Page or Product for web app, mobile app or service is similar most often completely the same properties and collections, especially if your Models/DTO are very clean, lean, POCOs.

Oren,  I followed your approach of not implementing a Repository pattern (since most examples of RavenDB don't do it) and I got to a mess of code within my MVC controllers. Each one dealing directly with Session and retyping the same code all over the place. For instance, the CRUD views. They are all loading data from RavenDB and there's lots of code duplication and lots of repeating mappings, even when using mapper libraries. 

This was the first time when I started to notice I am having issues and I don't like my code done like that. I still left it the way it was until recently I was faced with having to implement a Service Stack service. 

Given that I followed SS's and Martin Fowler best practices and reinvented DTOs here instead of using viewmodels I was once again faced with mapping. So I had to copy/paste all the data loading and mapping functionality that was already done in the controllers to my SS service.

Now I really knew I had big problem and I instantly knew this whole mess would have been avoided if I went with the repository pattern in the first place and have providers do all the DAL/BL work and just serve both controllers, web services, console applications (if they come along someday in the future), etc.

Also, if I decide to switch to Mongo or Redis someday, since they are both free and could be an option in some projects, I have made it very easy to do so, just implement the Interfaces with specific DB logic and correct the DI bindings. 

Since I now provide Repository Interfaces to my controllers, instead of the almighty IDocumentSession, I can switch easily.

I wish I never brought IDocumentSession to my controllers because it was great deal of work to remove it and strip everything out to repository providers.

The problem is, however, some things are hard to do with Raven and Repository pattern. Currently I'm having issues with how to implement RavenDB Statistics from Repository.

Kijana Woodard

unread,
Mar 29, 2013, 8:52:50 AM3/29/13
to rav...@googlegroups.com

And your last paragraph is precisely what is wrong with repository. You can't expose the interesting features from raven/mongo/redis without making a mess of throw not implemented. Repository will only work if you have interchangeable dbs. Raven/mongo/redis/mysql/postgres/sql server/oracle are not interchangeable unless you stick to the most basic functionality.

Statistics, include, async, suggest are features I can point to off the top of my head that won't fit into the typical GetById repository.

Likely there were many other ways to Dry your code. We can explore if you like.

At the end of the day, to be optimal and simple, some code needs to understand the needs of the viewmodel and the capabilities of the storage engine. The controller can serve this role, but so can other classes that the controller invokes. The advantage I see to the latter is that different bits of functionality can be served from different or multiple repositories.

--
You received this message because you are subscribed to the Google Groups "ravendb" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Mircea Chirea

unread,
Mar 29, 2013, 9:14:32 AM3/29/13
to rav...@googlegroups.com
You could move that code into a common project. There many different ways.

But the most important part: it is very clear what everything is doing. Why does it matter that all queries are similar, hence a lot of code is identical, except in a few places? You can only de-duplicate up to a point; beyond that it's not feasible and makes things worse.

If you use say AutoMapper you've essentially removed most of the duplication. One last thing is, if you use the same queries in multiple places, is use command/query objects - you just pass them a session and they do their magic.

mare

unread,
Mar 29, 2013, 9:34:34 AM3/29/13
to rav...@googlegroups.com
Well, that common project you talk about is a repository in my case. Not exactly a Business Layer but similar. 

My issue was:
To prepare a ProductViewModel for an MVC view I have to go through various utilities and services. Load up the Product (model class) from the datastore, map to view model, calculate prices, populate images collection from images that are stored on disk, which is handled by UploadsManager, populate product file attachments (like PDFs) which is again done by a helper class that reads it from disk (I don't store binary data in DB and after seeing prices for cloud based RavenDB I am more assured that this was the correct decision).

So the calculation, images and attachments parts were already present in outside layer.

As such in my controllers I'd this:
1. Load Product (IDocumentSession)
2. Calc prices (outside)
3. Image and files (outside)
4. Map (ValueInjecter)
5. return view with viewmodel

It looks like jumping through the hoops and that's what it truly is. This is too much for controller so it has to go elsewhere. Leaving only the IDocumentSession part in controller makes no sense. 

Why?

Because one day a request for a API (web service) comes along.

Now go implementing web service and do all of the above steps again in a web service. Nonsense.

Now you start seeing that you have to move everything elsewhere and then you end up with this:

MVC Controller:
1. Request already mapped ProductViewModel from some layer
2. Return

API Service:
1. Request already mapped ProductDTO from some layer
2. Return

You still have an option to cater for different clients (the ProductViewModel and ProductDTO can hold the same information or not). You are left with all the loading/mapping/transforming code in one place.

I know DBs mostly are not easily interchangeable, that's not the primary goal I am chasing here. If repository in the end does help, fine, collateral. The primary goal is simplicity, having everything in one place and control over what you give your users/developers access to.

Paul Hinett

unread,
Mar 29, 2013, 9:40:59 AM3/29/13
to rav...@googlegroups.com
As an option why don't you have an Api service, and have your MVC
controllers talk to your Api service?
> one place and _control_ over what you give your users/developers
> /dis-connect/ the structure and use the repository
> pattern or some custom form of it.
>
> In all cases, I use it and the "extra" abstractions
> helped me scale my project structure without problems.
>
>

Khalid Abuhakmeh

unread,
Mar 29, 2013, 9:47:02 AM3/29/13
to rav...@googlegroups.com
@mare you are heading down a road that is filled with pain and tears. I know cause I used to be a proponent of the Repository pattern until it just fell apart on me in a spectacular way. In my opinion you can never get a repository without it being leaky. I've tried on Linq2Sql, Entity Framework, Stored Procs, RavenDB, and more.

If you find yourself repeating queries all over the place, then I would guess you have some code smell. Let's say you don't. It is very easy to refactor your queries into something that is reusable. You have two options: 

1. Make extension methods that hang off of IDocumentSession so that you can get a query like "session.GetUserByEmail(email);"
2. You could make tasks that take an IDocumentSession. "new GetUserByEmailTask(session).Execute()". 

This give you the advantage of leveraging the power of your DB without going down to the lowest common feature set. Like you last line says, "The problem is....". You'll be saying that a lot soon, and I wish you good luck.

mare

unread,
Mar 29, 2013, 9:47:29 AM3/29/13
to rav...@googlegroups.com
I thought about that and it's pretty much the same thing to what repository providers do. If It's still an abstraction so it suffers from almost the same issues Kijana pointed out.

mare

unread,
Mar 29, 2013, 9:51:57 AM3/29/13
to rav...@googlegroups.com
I'd like to explore more options. Where can I find more info on extension methods to IDocumentSession? are those regular C# static extensions?

@Mircea also talked about command/query objects. What are those?

Khalid Abuhakmeh

unread,
Mar 29, 2013, 9:55:26 AM3/29/13
to rav...@googlegroups.com
@mare There is a difference between encapsulating, and abstracting. When you are encapsulating your logic you still know that you are using RavenDB / Redis / Mongo. Abstracting tries to hide that fact (not very well imho). They are not the same thing.

Khalid Abuhakmeh

unread,
Mar 29, 2013, 10:00:25 AM3/29/13
to rav...@googlegroups.com
yes I would do something like this.

public static class DatabaseExtenstionMethods {
public static User GetByUserEmail(this IDocumentSession session, string email) {
return session.Query<Users_All.Result, Users_All>()
.Where(u => u.Email == email)
.As<User>()
.FirstOrDefault();
}
}

Now you can store all of your repeating queries in here and reuse them across your codebase. You can now also use these same extension methods in your unit tests without having to mock up a new type of repository every time you deal with a new Repository<T>. You can use the RavenTestBase across all your tests and keep it simple.

mare

unread,
Mar 29, 2013, 10:06:35 AM3/29/13
to rav...@googlegroups.com
In the end there's a place where data retrieval has to be made and we need to talk to specific DB. I just want that place to be only one. Whether it is API service that does the plumbing, fine. If it's repository, it's fine for me too.

I just don't want my API services use IDocumentSession for themselves, my controllers for their needs, command line application for itself etc. You get the point.

mare

unread,
Mar 29, 2013, 10:09:13 AM3/29/13
to rav...@googlegroups.com
Thank you, I guessed correctly. This does look interesting, didn't thought of it before. Will definitely try it for custom cases where I might need Statistics out of a query but need it only in one place and for something really exotic. 

Khalid Abuhakmeh

unread,
Mar 29, 2013, 10:11:06 AM3/29/13
to rav...@googlegroups.com
I understand what you are saying, you have some overlap between your Controllers, WebAPI endpoints, and command line; you would like it to be consistent. I would go with with the extension methods then, but keep in mind that these three things might diverge at some point, and when they do it will be nice that you do have the IDocumentSession.

mare

unread,
Mar 29, 2013, 10:11:52 AM3/29/13
to rav...@googlegroups.com
However, this still requires that I expose IDocumentSession to the controllers, right? Through constructor injection or how?

Khalid Abuhakmeh

unread,
Mar 29, 2013, 10:21:15 AM3/29/13
to rav...@googlegroups.com
Yes you still need the IDocumentSession passed in somehow. You could pass it in to each new controller, or I like creating a base controller that can pull it out of the DependencyResolver in MVC / WebAPI. The base class gives you a lot of consistency and the ability to build some good patterns in your code base.

public abstract class ApplicationController : Controller {

protected virtual IDocumentSession Db { get; private set; }

protected ApplicationController() {
Db = DependencyResolver.Current.GetService<IDocumentSession>();
}

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
  // handle saving your session possiblly?
}
}

Kijana Woodard

unread,
Mar 29, 2013, 12:28:54 PM3/29/13
to rav...@googlegroups.com
I think the problem with repositories is granularity. It's nigh impossible to abstract away all the building blocks of the underlying store while retaining flexibility. To my earlier list of "hard to abstract, I'll add: changes, Lazily, Customize, Advanced.Lucene, Query<T>.Search. 

I think we all agree that making a generic repository would hide all that and any abstraction that exposes that wouldn't be much of an abstraction.

The compromise I am experimenting with is the idea of a chunky repository:

RavenHighValueCustomerViewModelProvider : IHighValueCustomerViewModelProvider

I would lean heavily on ISP and only expose the one method a controller would need to get the view model. 

Now maybe that's too chunky. Maybe what's needed is IHighValueCustomerProvider which is then composed with other things to build the view model by the controller. 

What you get here is options. It doesn't have to work the same way throughout the app.

To be clear, the only reason I am going down this road is because I have a particular situation to overcome. I have customers running on a LAN that is often disconnected from the web and they will have no more ~11 people using the app. Running Windows 7/8 pro, this isn't a problem since there's a 10 simultaneous connection limit for IIS. It's not a problem, until someone want rudimentary chat. Ah, SignalR, but then you have persistent connections and the 10 connection cap is blown. So I could upgrade them to a server OS or use something like Nancy. Great. Installing under IIS for them (very non-technical users) is a pain. Command line / service sounds like a winner. But will it be Nancy or Service Stack. I'm not sure.

The "not sure" part is where I think to pull the Raven out of the controller.

Also, think about having more SRP with Controllers. MVC pushes us to have controllers with dozens of Actions. I'm finding some gains following FubuMVC's model of a single Action per controller. Maybe 2 for Get/Post. Maybe. :-D

The core idea is to arrange code along slices of business functionality rather than along technical concerns of UI/DAL or even with concerns for "Entities". The advantage is that when I decide to implement some functionality with Redis, it stands on it's own.

Most system re-writes that I see stem from woefully non-architected code (select n+1, random data updates, etc) and woefully over-architected code (everything is SO Dry, it's unreadable and any deviation from the carefully crafted patterns topples the entire apple cart).

This approach takes a different mindset. However, once there is no such thing as "THE" repository, then there doesn't need to be "THE" database and there doesn't need to be "THE" Customer entity. Options open up. But options means more responsibility. There still isn't a silver bullet. :-)

All in all, the "simplest thing that will work" rule applies. If using extension methods on IDocumentSession makes the code more manageable, use it. If you need more indirection, fine. The good thing is the entire app doesn't _have_ to be the same. It's a little more shocking to someone new to the app to absorb different approaches, but homogenization isn't necessarily a win if you end with endless hacks (if statements) or simply can't deliver business value because it doesn't fit the common approach.

I like to start extremely naive and refactor once the pain starts. My problem is that I find patterns too easily and start trying to DRY out the code too quickly. When I realize there really are undiscovered business requirements, it's painful to unwind all that DRY code to accommodate the differences.




mare

unread,
Mar 29, 2013, 5:23:44 PM3/29/13
to rav...@googlegroups.com
Kijana, this is a great post you just posted and this entire thread already opened up few new possibilities for me and I like this way how everyone contributes his own thoughts. It is interesting to read how a thing such as implementing a web application can also impact server infrastructure decisions.

I do think service segmentation/repository/data retrieval options are some of the topics under-emphasized in the official RavenDB docs, too much attention is put on the IDocumentSession inside controllers approach.

I think I will follow the way of having a general repository but have those extension methods around for advanced functionality. Maybe at some point in the future even build out a service on top of those extension methods and then get rid of the repository.

The only thing I really found difficult since I just done that and it took me two days is refactoring controllers to remove IDocumentSession - there's dozens of _session.Query<>() calls and it's just so painstakingly heavy and cumbersome even when you use Resharper or VS refactoring options. 

David Zurillo

unread,
Mar 30, 2013, 3:29:31 AM3/30/13
to rav...@googlegroups.com
I'm new to raven, so can't really comment on the API too much, but I use the repository pattern and haven't got into too much trouble due to API. But I denormalize a LOT! So most of my raven usage is just loads, ill save the query for where raven should shine and that is searching. After all as someone mentioned its a document store and being such you should try to load over queries as much as possible(ie you need to think more about storing stuff in a document fashion, not a relational fashion).

So my repositories are very thin wrappers. But I'm still very much datastore technology argnostic, which is always a good thing. Especially if your domain outlasts the technology you inject to do infrastructure stuff.

Kijana Woodard

unread,
Mar 30, 2013, 9:16:27 AM3/30/13
to rav...@googlegroups.com

The main thrust of my argument us that being data store agnostic is a mistake and is rarely a good thing.

Its working for you because you're not using any interesting features of the data store.

How agnostic can your repository be if you're using sql server hierarchy ids or raven spatial?

At that point, the generic repository is a lie. If you ever change persistence engines, endless pain ensues.

A better approach, if its actually needed, is to encapsulate chunks of business functionality.

Pretending all db engines are perfectly swappable is not a win. Its extra work, harder to maintain, and won't actually help if you actually switch db engines.

On Mar 30, 2013 2:29 AM, "David Zurillo" <david....@gmail.com> wrote:
I'm new to raven, so can't really comment on the API too much, but I use the repository pattern and haven't got into too much trouble due to API. But I denormalize a LOT! So most of my raven usage is just loads, ill save the query for where raven should shine and that is searching. After all as someone mentioned its a document store and being such you should try to load over queries as much as possible(ie you need to think more about storing stuff in a document fashion, not a relational fashion).

So my repositories are very thin wrappers. But I'm still very much datastore technology argnostic, which is always a good thing. Especially if your domain outlasts the technology you inject to do infrastructure stuff.

Kijana Woodard

unread,
Mar 30, 2013, 9:23:23 AM3/30/13
to rav...@googlegroups.com

One other point. I try to achieve Load as much as possible as well.

But I wouldn't say that using Query goes against the concept of a document store. In fact, being able to do full text queries to find documents is fundamental.

I would say that setting yourself up to do Loads is a design/optimization point.

And Query != Relational Join.

devm...@hotmail.com

unread,
Mar 30, 2013, 9:50:02 AM3/30/13
to rav...@googlegroups.com
I Agree with David Zurillo, 

lately i have learned, that with RavenDB you can approach the solution in many ways, but Denormalizing Data where it makes sense is a lot better than Query Joins, and with the new Script Patch API you can make Bulk Changes when you require that.

Kijana Woodard

unread,
Mar 30, 2013, 10:03:13 AM3/30/13
to rav...@googlegroups.com

I agree that setting up your customer facing app so that it can mostly load is a win. Semantic ids are a win here for related data in many situations. Denormalizing data that doesn't or very rarely changes is fine.

Doing lots of denormalizing/patching as an app standard seems counter productive.

A generic repository is a loss.

devm...@hotmail.com

unread,
Mar 30, 2013, 10:17:10 AM3/30/13
to rav...@googlegroups.com
Kijana, i totally agree that Doing lots of denormalizing/patching as an app standard seems counter productive.
but you will only need it in rare cases, if you take care of how you model your App, and i think you do agree that each technology or method has its compromises, but in RavenDb case, my humble opinion is that it is very very less than others like SQL Server Join Hell for example :)

Kijana Woodard

unread,
Mar 30, 2013, 11:01:16 AM3/30/13
to rav...@googlegroups.com

Indeed

ms007

unread,
Mar 30, 2013, 6:12:12 PM3/30/13
to rav...@googlegroups.com, justin...@stargategroup.com.au
I do use the repository pattern with RavaenDB.

At first I dismissed it, but then I came back to ig again, mainly for the following reasons:

1) In our project we have several applications (A Windows Service, an Update Console and the Web Application) that 
require the same data queries. But the application should not share the same service layer and therefore I 
would have code duplication, if I had to implement these queries several times. And the code would be 
spread over multiple projects.

2) Our system is multy tenancy capable and actually all data queries must open a session with a specific database.
It is recommended that testing for RavenDB is performed with the EmbeddableDocumentStore. But 
EmbeddableDocumentStore does not allow to _documentStore.OpenSession("myTenantDatabase") which is what I have to
use all the time. Therefore our tests were too complicated and too slow. Whereas, a repository is very easy to mock.

3) In our project not all developers know RavenDB equally good. Therefore, the data access code is encapsulated in a
Library and the less specialized developers work only with the repository interfaces. The implementation is done
by a RavenDB connoisseur.

The use of repositories is not free. We have the following disadvantages with the use of repositories:

1) Session Handling: To avoid problems with sessions we use for each action a new session.
This comes with some minor performance losses
 
2) Projections: We must implement all projections explicitly as classes and can not use anonymous Types.

3) Even we avoid code duplication we write more code because the overhead of the additional library.
  
The decision was not easy for me, but the benefits outweigh. 
In another project, it may again be quite different.

A general statement can not be made in my opinion as it always depends on the current problem at hand
and the advantages and disadvantages should be compared.

Khalid Abuhakmeh

unread,
Mar 30, 2013, 8:20:22 PM3/30/13
to rav...@googlegroups.com, justin...@stargategroup.com.au
Sorry to be so vocal about this topic, but I truly feel the repository pattern is just not good for a domain you have complete control over. If you build a repository for a Web API that's one thing, but not your own code. Please don't use the repository pattern. It will only end in heartache. The issues you described below are easily overcome, with just a bit of work. You get to keep the IDocumentSession and tackle all your issues. I am only speaking from the experience being a recovering repository user.

On Saturday, March 30, 2013 6:12:12 PM UTC-4, ms007 wrote:
I do use the repository pattern with RavaenDB.

At first I dismissed it, but then I came back to ig again, mainly for the following reasons:
 

1) In our project we have several applications (A Windows Service, an Update Console and the Web Application) that 
require the same data queries. But the application should not share the same service layer and therefore I 
would have code duplication, if I had to implement these queries several times. And the code would be 
spread over multiple projects.

I described two methods above that would allow you to share logic, without resorting to the repository pattern: Extension methods and or Commands/Query objects. The advantage here is that each domain (windows service, console, web app) now has the document session and can do something that doesn't cross all domains. Your console app might be doing batch inserts and seeding your database, and you probably want to keep that in the console.
 

2) Our system is multy tenancy capable and actually all data queries must open a session with a specific database.
It is recommended that testing for RavenDB is performed with the EmbeddableDocumentStore. But 
EmbeddableDocumentStore does not allow to _documentStore.OpenSession("myTenantDatabase") which is what I have to
use all the time. Therefore our tests were too complicated and too slow. Whereas, a repository is very easy to mock.

You can solve this issue by just moving the _documentStore.OpenSession into an IoC Container and having it (the container) resolve the session for you according to the context. I usually do this by looking at data found in the HttpContext / Cookie. It works nicely and then all my controllers end up just depending on a IDocumentSession. This makes it easy to test with the EmbeddedDocumentStore and no need to create any special mocks. I've built a multi-tenancy site that has 10 current tenants with no issues.
 

3) In our project not all developers know RavenDB equally good. Therefore, the data access code is encapsulated in a
Library and the less specialized developers work only with the repository interfaces. The implementation is done
by a RavenDB connoisseur.

Not all developers are created equal, that is the world we live in, but we all have the ability to learn. You might be selling them short here. I agree there are a few concepts to learn with RavenDB, but they are not very difficult. Also RavenDB behaves slightly different than relational databases, so a user of your repository might be confused when the behavior is not what they expected. This means your repositories "abstraction" is going to leak fast.



The use of repositories is not free. We have the following disadvantages with the use of repositories:

1) Session Handling: To avoid problems with sessions we use for each action a new session.
This comes with some minor performance losses

You could avoid this even when using the repository pattern, you just need a IoC container or better lifetime management. I go with StructureMap usually so I don't have to write too much code.
 
 
2) Projections: We must implement all projections explicitly as classes and can not use anonymous Types.


I think this is ok. Projections as classes are better since they express intent better than anonymous types. 
 
3) Even we avoid code duplication we write more code because the overhead of the additional library.
  
The decision was not easy for me, but the benefits outweigh. 
In another project, it may again be quite different.

A general statement can not be made in my opinion as it always depends on the current problem at hand
and the advantages and disadvantages should be compared.


Let me state again. The repository pattern is usually a leaky abstraction and I would avoid it. I've heard people say "well RavenDB is just trying to tie you into their database." and I think that is just cynical. I think the truth is, any ORM / Database creator wants you to to have all the power of that database at your fingertips, and when you use the repository pattern you are cutting those fingertips off.

 

David Zurillo

unread,
Mar 30, 2013, 8:21:49 PM3/30/13
to rav...@googlegroups.com
Whoo down mate. I use combguids for ids the I generate, I don't leak ravendb or SQL or whatever into my code. The client API thank goodness takes care of the ravendb specific stuff, so you don't have to. Or am I missing something?

I use natural keys or comb guids where each are required.

Eg guid for persisting model docs. A natural key might be an emailaddress for a usersbyemailaddress doc.

And I only use this for read models (reads). My write side is an event stream only (see cqrs with eventsourcing).

Btw: A session is always (well with datastore technology ive used) required so my repo's have a generic context/session that any layer manages(opens and closes).

David Zurillo

unread,
Mar 30, 2013, 8:24:51 PM3/30/13
to rav...@googlegroups.com
Btw I've seen and worked on far too many project the had SQL or linq code spread all over the place and leaked domain logic everywhere and they are big balls of mud. Exposing data store out is the first sign of this potential problem as it can easily lead to being an enabler of this type of spaghetti.

Mircea Chirea

unread,
Mar 30, 2013, 11:39:00 PM3/30/13
to rav...@googlegroups.com, justin...@stargategroup.com.au
There is one problem the repository pattern solves: abstracting similar operations across data stores.

So, say, if you are making a library that needs to load some objects from a database, it doesn't care how they are stored or loaded, as long as the only thing it does is GetById and maybe Save. That is how session and memberships providers for ASP.NET work, but their required operations are so simply you could reliably implement them with flat files. But if you need to run more complex queries, the repository pattern shoves the complexity under the bed; except the bed is no longer sitting flat, as you can't abstract perfectly.

Use command objects, if you need to share queries across several applications. Just feed the command object any IDocumentSession and let it do its work; at the end have it return the results. Of course this will only work for queries or updates, you will never be able to abstract the changes API with command objects, for example.

public class GetLoyalCustomersCommand : IDatabaseCommand<GetLoyalCustomersCommand.Result>
{
    public class Result
    {
        // result properties go here
    }

    // command/query properties go here
    
    GetLoyalCustomersCommand.Result IDatabaseCommand.Run(IDocumentSession db)
    {
        // magic goes here
        
        return result;
    }
}

That's what I used when I had to share queries (albeit with Entity Framework, but you get the point). I would execute it like this:

var result = Database.Execute(new GetLoyalCustomersCommand
{
    SomeInput = "weee",
    SomeNumber = 4,
});

On Saturday, May 21, 2011 9:24:46 AM UTC+3, Justin A wrote:
Hi folks,

are any/many people using the Repository Pattern with RavenDb? As I
start learning RavenDb, my first reaction was to do this. And it works
fine. But I keep feeling that my Repository Pattern wrapper is just a
waste. Now -> i'm trying to be vary careful here because i don't want
to start a debate about the use of patterns and interfaces to remove
dependencies, help with mocking / testing / tight coupling, etc. ~~
This is not what I'm asking about ~~

I'm just curious if people are using it with RavenDb, for whatever
reason(s) :)

If you are, can u say why?
If not, can u also say why :)

I'm really really curious.

-Justin-
Reply all
Reply to author
Forward
0 new messages