The Data Access Layer (DAL) Explained

By Mike on 18 November 2012

When you're building software, more than 99% of time you'll have to deal with a storage of some kind, mainly a database or (increasily) cloud storage. But years of experience (read: failure) taught the developers that it's best for the application not to be tightly coupled to a specific storage system.

Thus the Data Access Layer aka Persistence Layer was born. Simply put, the purpose of the DAL was to hide storage access details enabling the rest of the application to deal only with something called Persistence or Storage, an abstract representation of the actual storage system. This means that the app doesn't need to know about Sql or queries or any other specific details. The DAL provides the rest of the application with objects which are used to work with the storage: the Data Access Objects (DAO).

But a DAL is more than a group of DAOs. It contains EVERYTHING related to persistence: DAOs, entities which model how the data is stored - if you're using a (micro) ORM and other internal services used by the DAOs. However the app accesses the DAL only via DAOs, which can be considered the 'entry points' of DAL.

Note that the DAO itself is just a concept and it's used as an abstraction, that is the application doesn't know about the concrete object, it knows about an interface providing the desired functionality. The DAO has intimate knowledge about the storage system but it exposes only behaviour which makes sense for the application i.e a DAO should never expose or require information that is tied to a specific storage system.

Most of the time you'll here about repositories and ORMs. While a Repository is a concept, it is implemented as a DAO, at least from the application point of view. In fact every object used to deal with the storage is a DAO, but the Repository is a specialized DAO. It deals only with Business Objects and acts as a facade for other lower level DAOs (such as an ORM).

The ORM tries to present a relational database in an object oriented way. It abstracts actual database access (that's why it's a DAO) but still deals with specific database concepts as the entities defined model the storage structure, the way data is saved.
For many (CRUD) applications it can be enough and the application can use the objects returned by the ORM without caring that they are modelling persistence. For applications with complex behaviour, usually business applications, the Repository it's a better choice as most of the time a business object is different than the way it's persisted.

While the Repository and the ORM are the most commonly used DAOs, in practice you will use other DAOs too for different purposes, but hey don't have (yet) specific names.

You'll have DAOs which will deal with queries, returning a view model. I used to call these 'Query Repositories' but I think that 'ViewModel Repositories' is a much better name. Note that the 'ViewModel' part is valid for probably 90% of cases, but it can be replaced with other name representing the type of data returned so for example you can have  Reports Repositories (SalesReportsRepository, FinanceReportsRepository etc). In the end it's a naming issue but the essence is there are DAOs specialized in getting data for a definite purpose.

There are also what I call Persistence Services which are DAOs which deal directly with the storage system for operations that don't imply Business Objects or View Models or queried data. They manipulate the storage as a resource directly. One example of operation is updating the page views for a post or to check if an item exists in the database. They are simple operations which don't naturally fit a repository.

You might see in practice Query Objects which are used to encapsulate a query criteria to from ad-hoc queries, however each query object encapsulate only one operation. A repository or a service group together related operations.

The DAL is an important part of an application and you have to be careful not to let storage access details to be exposed (that's  called a leaking abstraction). A properly designed DAL will allow the change of a storage system without requiring ANY change of the rest of the application.

Repository vs DAO

By Mike on 1 November 2012

You're right, it's confusing! You have the repository which abstracts the persistence access details and you have the Data Access Object (DAO) which used to .. abstract persistence access details. So, is there a difference between those two, are they the same thing with different name?

Well, once again the devil is in the details. In many apps, especially data-centric, DAO and a repository are interchangeable as they do the same job. But the difference starts to show up when you have more complex apps with complex business behavior. While the Repository and DAO will strict abstract the data access they have different intentions in mind.

A DAO is much closer to the underlying storage , it's really data centric. That's why in many cases you'll have DAOs matching db tables or views 1 on 1. A DAO allows for a simpler way to get data from a storage, hiding the ugly queries. But the important part is that they return data as in object state.

A repository sits at a higher level. It deals with data too and hides queries and all that but, a repository deals with business/domain objects. That's the difference. A repository will use a DAO to get the data from the storage and uses that data to restore a business object. Or it will take a business object and extract the data that will be persisted. If you have an anemic domain, the repository will be just a DAO. Also when dealing with querying stuff, most of the time a specialized query repository is just a DAO sending DTOs to a higher layer.

Recently, someone told me that my repository approach is just a badly named DAO and it doesn't match Martin Fowler's definition of the Repo. Well, besides what I've said above, there is something else when dealing with the repository pattern. I tend to apply a pattern according to its spirit and intention, not as a dogma.

We have the definition: "Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects. A system with a complex domain model often benefits from a layer [...]  that isolates domain objects from details of the database access code".

So the intention of the repository is to isolate the domain objects from the database access concerns. This is the important part. The fact that the repository is using a collection-like interface, doesn't mean you MUST treat it as a collection and you MUST have ONLY Add/Remove/Get/Find functionality. Really, it's not a dogma and you don't have to apply it by the letter.

Let's think a bit. The pattern is used to acheive separation of concerns and to simplify things. If you force yourself to use a collection and a criteria and some unit of work (things that made ORMs very popular) in probably 99% of cases you just complicate things. And it's quite ironic that people are using ORMs or some other Unit of Work approach to apply the repository pattern forcing their domain objects to include data access related stuff (like making properties virtual for NHibernate or needing to provide a parameterless constructor etc). What's the point in using the repository pattern if you couple your domain objects to data access details?

Back to Repository and DAO, in conclusion, they have similar intentions only that the Repository is a higher level concept dealing directly with business/domain objects, while DAO is more lower level, closer to the database/storage dealing only with data. A (micro)ORM is a DAO that is used by a Repository. For data-centric apps, a repository and DAO are interchangeable because the 'business' objects are simple data.

Do We Need The Repository Pattern?

By Mike on 10 October 2012

Just when I thought I've covered anything related to the Repository Pattern, Jimmy Boggard writes this and this . Since I consider the Repository Pattern the easy and intuitive way of dealing with storage concerns, I'm always baffled how other devs seem to consider it a complication or not needed. I'm really starting to ask myself if I've understood the pattern correctly. But even if my view of the pattern is -let's say - extended and maybe it's actually another pattern or a combination, I still find it the most natural way of abstracting the persistence.

One thing I keep seeing popping up is the if you're using an ORM what's the point of the repository? You can read my post Repository vs ORM for more details, but in short, the ORM only 'hides' a handful of RDBMS. Change the RDMBS to a NoSql and the ORM becomes useless. Yes, you might not change the db very often but the point of a repository is not to hide a db engine, it's to abstract the whole storage.

In an application, you might deal with different storage at once: local db, xml files, cloud storage etc. The Repository pattern hides all those and gives to the rest of the app an interface: get me this, save that. Where and how is not the app's problem.

Let's work a bit on Jimmy's example. We have the simple case of a blog engine and a controller action which returns a list of posts. But querying the RavenDb in the controller is ugly (hard to maintain - fat controller symptom) and the elegant solution is to use a query object which encapsulates the actually query, pretty much a facade.

For me this approach is actually a bit of the repository pattern, because that why you're using a repository in the first place. Yes, to abstract anything storage related and to provide a facade that makes sense from the business point of view. A 'GetPosts' method says more that a 5 lines long Linq. It helps with maintainability.

But about those repositories with dozens of methods? Well, split them. That's why you're using interfaces, are you telling me that you'll use all those methods in one controller? If so, then that repository is actually needed for that controller. But if the controller only uses 2-3 methods, extract an interface and use only that.

Furthermore, a repository usually serves a bounded context. The PostsRepository from the Domain is very different than the PostsRepository from the UI (different bounded contexts). The latter is usually named something like PostsQueriesRepository PostsViewModelsRepository(in fact it will be an IQueryPosts interface) to avoid confusion.

I was asked a few times, what's the difference between a repository and a DAL interface. The repository is a high level concept  used to access the persistence. It's implemented in code first as an interface (most of the time) defined where(in any layer) you need it. The actual repositories implementations reside in the DAL (Persistence Layer). And you can say that a repository contract is an entry/exit point of DAL, while its implementation is a a part of DAL. So the DAL is made up from ALL the repositories and ALL of DAOs, ORMs, ORM entities and utilities, pretty much everything directly related to accessing the storage.

It seems that most of the devs are considering a Repository just a way of hiding a db or worse, a wrapper over the ORM. It's a bit more than that, it's a high level abstraction which helps separate the Persistence Layer from the rest of the app. It also provides a meaningful facade from the business point of view, thus helping with maintainability.

Repository Pattern Revisited With An Example Of Advanced Usage

By Mike on 18 July 2012

I've described the Repository Pattern in a previous post. Those things are still valid but I want to emphasize a few aspects and to present a scenario of advanced usage.

First of all, it seems to me that way to many developers believe the Repository is there just to hide the database.Probably that's why a number of them don't understand why you need a repository when you have an ORM. Hiding the db is just one function of the Repository as it does other, more important things.

We know that the rest of the application talks to a repository when it wants something persistence related. The Application sends and receives application objects (business objects and DTOs for the view model) from the Repository, without caring what the repo uses to actual store the objects. In the majority of cases, it will probably use a (micro)ORM like EF or NH, but no matter the underlying library, the repo has to return or to handle application objects that have no relation to an ORM's entity.

This means that the Repository must 'translate' application objects to ORM entities and vice versa. The repository is pretty much like a criogenic machine: it takes something and freezes it and then unfreezes it when asked, returning a perfectly valid object exactly as it was received. So the Repository has a more active role than just simply hiding a storage device, the repository IS the governor of persistence

There isn't just a single Repository either. There are as many repositories as bounded contexts, because a repository should serve only a specific context. It might be related to persisting Domain entities or just to query and return view models , the important thing is that there are as many repositories as needed by the application.

I've said above that a repository sends back a business object when asked. But if the object is saved in 3 related tables, how does the Repository knows how to construct it? That's easy, Mike, just pass a factory to the repository's constructor and let the factory handle it. Well, I think this approach might not be the right one for 90% of the cases and that's because a repository restores an object, it doesn't create a new one. Semantics I know, but they do matter. I think it's important to make the distinction between restoring and creating a new object, especially when dealing with Aggregate Roots.

There are a number of ways to restore a complex object, I favor two:

  •  save and load a memento (a dto containing the object state) and then pass it via the object constructor, which can be a static factory method of the object;
  •  use Event Sourcing and store everything a a stream of events. When restoring the object, just pass the stream as constructor argument (this is the standard way to restore an object using ES).

When dealing with queries, things are even simpler: the repository returns a DTO and there are a number of ways to get one.This is a trivial matter and outside this post.

Advanced Usage

Now let's go a bit deeper into the rabbit hole and let's use the repository in a more advanced way. For simplicity let's consider this scenario: we have a blog (yes..) with posts and pages. Both support visibility options: they can be public or private.

public interface IVisibility
{
     int Id {get;}
	 bool IsPublic {get;set;}
}

public class Post: IVisibility { }

public class Page: IVisibility {}

When creating a post or a page we can set their visibility but we want to to that after wards, from the admin page. Assuming we use a task based UI, this means that a request is sent to the server to change visibility for the item with id=5.

But , what do we ask the Repository for? A post, a page? How about we ask it to give us an object for which we can change the visibility? It is pretty much what we want, we don't really care if it's a post or a page, it's an item you want to make private. So how about this?

var item=repository.WantToChangeVisiblility(id);
item.IsPublic=false;
repository.Save(item);

public interface IRepository
{
   IVisibility WantToChangeVisibility(int id);
   void Save(IVisibility item);
}

What do you see? It's obvious that the intention is very clear, also the app receives an object which allows one thing only. If the repository would have returned a Post or a Page object we would have 2 issues:

  •  An explicit Post/Page will alow you to do more that change visibility. And maybe you don't have areason to do that now, but give it time. And if you don;t find a reason, I'm sure a junior developer working with that code will find one in no time.
  •  The repository must populate a whole business object which, depending on the desired action, can be just waste of resources. In this example, why should it load a Post with all the details and 300 comments, just to modify its visibility?!

Ok, all interesting and that, but how do we implement it in the repository? Like this:

internal class ItemWithVisibility:IVisibility{}

This class is defined in the DAL, it's an implementation detail. When the app asks for an IVisibility, the repository returns an instance of ItemWithVisibility containing only the relevant information. Easy and lightweight. And by the way, this simple object can be considered the Aggregate Root for that context. Of course, you might have a fully AR defined in the Domain which will look the same. Note that the AR is simply the object 'representing' a bounded context, it doesn't need tot be complex it that particular context doesn't require it.

This is an elegant way to use the repository in synergy with the rest of the app. It's a waste to treat the repository just as a simple dumb wrapper to hide the db, it can do more for your application.

Don't Use ORM Entities To Model The Domain

By Mike on 20 April 2012

Initially I wanted to include this in the Entities and Value Objects explained post, but I think this matter deserves its own post.

When you model the Domain, for your own good FORGET about databases, ORMs etc! Because the design of the model must be dictated by the domain. If you put an id in a domain object, then it better have its use within the Domain. Keeping that code clean, will make the code much easier to understand and to modify.

 If it happens that a type will be persisted with an Id because that's what the ORM wants, you should NOT change the Domain model. Put the id in the Persistence Model and leave the Domain Model as it was.  If you change the Domain object just for the sake of another layer, in fact just for the sake of a different BC, that model becomes inconsistent within its BC. Yes an Id doesn't change much or making a property virtual (because that's what the ORM requires), but it tells to a future maintainer that it's ok to subclass the type and override a property, because well... that's why is virtual in the first place, right?

 What do you do, you put in the comments : "this is in fact a Value Object but we need the Id for NHibernate, DO NOT change!" or "This property is virtual because EF requires it"? Come on, you want to do DDD and have a robust code, or you just want to throw buzzwords around, while continuing to do the things 'the old way' ? If that app, switches to use Redis or MongoDb, an ORM becomes useless, but hey, your 'domain' objects are tied to the ORM requirements so you just keep them. Of course, now any (new) developer will the comments then asks himself: "Huh, we don't use NHibernate... Wtf is this?!"

 The objects , entities that you define for ORM use are for ORM use ONLY. Those objects must evolve according to the storage needs. If you used them for the domain, you'll have an abomination, the entity will serve two masters and none of them well. Any time you'll change one because one master needs it, you have to account for the effects from the other master. You know not to mix the UI with calling the db, why do you think is ok to use a Persistence implementation detail as the base for your Domain?

 "It's about DRY" you might say. I like DRY, but here you just invoke it as an excuse for mixing responsibilities.  You don't have identical code in two layers, they might 'share' 90% but they are different and those differences matter. Those will give you the headaches. Even if at one point they are 100% identical: each code was written with DIFFERENT INTENTION in mind. It just happened to be identical. If you keep them separate, then one can change without messing the other.

 What about maintainability, you ask? This is maintainable code. The code you can understand in a second and you can modify in a minute. If you are worried about writing the same properties, there is an old technique which usually is abused but here it's very appropriate: it's called copy/paste and it will solve this specific problem in a second.

 What's more difficult: to copy/paste in 2 seconds every time it makes sense or to keep one code base and then praying that modifying something didn't break the functionality in another layer?

 That's why I'm a firm supporter of the separation of the Domain Model from the Persistence Model when using an ORM. The ORM docs might say that you model the domain entities, but in fact you'll be always modelling the Persistence Model because this the ORM's purpose: to handle the persistence of objects in a relational database. It's not its purpose to model domain behavior.

 Model the Domain entities for the Domain needs, model the Persistence entities for the Persistence needs. Don't forget that an ORM is ALWAYS an implementation detail of the Persistence.

The Repository Pattern Vs ORM

By Mike on 15 April 2012

It happens that every once in a while I stumbled upon this question: "Why use the Repository pattern when I'm already using an ORM?Isn't the repository redundant in this case?". Well, as always you have people arguing that the Repository is an anti pattern and the other who says otherwise. But who's right? Is it the repository useless when you have an orm? Let's find out.

An ORM is the acronym for Object-Relational Mapper and this term is a giveaway. It says clearly that it's purpose is to provide a bridge between the object oriented way(your application) and the relational way (the relational database). Pretty much any ORM will provide the application with a virtual oop representation of the database and will make it easy to CRUD without involving SQL that every developer loves. It also provides an abstraction over a specific rdbms, so it's easy to change let's say from MySQl to SqlServer with a simple config setting. However, if you want to use a NoSql db like MongoDb or RavenDb, you're out of luck. These are document databases not relational ones. An ORM is completely  useless here.

But with a RDBMS, it's very useful and it can simplify your work as a developer, especially if you don't like dealing with sql and specific db quirks. However it does come with a price: steep learning curve (it's not that easy to understand how to fully use NhIbernate or EF for example) and some performance penalties. It's also way to easy to intermingle it everywhere, forgetting that is in fact an implementation detail of how the app is persisting things(the fallacy of using the ORM model as the domain model).

And that's where we enter the Repository domain (sic). The Repository Pattern is an architectural pattern which abstracts and encapsulates anything persistence related. Now, the persistence medium can be a relational db, a document db, an in-memory db, a simple file, a cloud storage etc. It doesn't matter, as the Repository hides that. The application doesn't need to know all these details. The app doesn't care you're using MySql or RavenDb, it just cares that the persistence can store and restore objects.

The Repository pattern, allows the application to know only about abstractions. As far as the app is concerned, the repository is the place where objects are stored and retrieved. The Persistence Layer pretty much contains just implementations of specific repositories used by the app. And the repository implementation actually does the job. How it does it, it's an internal concern, an implementation detail of the Persistence Layer, so the app doesn't know nor care about it.

Of course, if you're using a RDBMS (as it's very common) you might use an ORM. Maybe it's easier for you to write the queries, maybe you want to change later to a different RDBMS. That's no problem, use the ORM, the Repository won't mind, but the fact that you're using a rdbms and an ORM is still an implementation detail, known only by the Persistence Layer. Further more, different repositories might use different storage systems. I can store most of the data in MySQl but I'm still storing images in the file system and the app only knows about a IFileRepository interface .  The actual FileRepository object may use the db to retrieve metadata about the files and the file system to return the files.

Thing is, within a repository implementation I can use ORM, rdbms, cloud storage, file system etc. I can change the implementation any time, the app won't care and it won't be affected by the changes.  That's why using the Repository Pattern makes it much easier to do TDD: you can mock it or stub it very easy.

In conclusion, an ORM and the Repository Pattern have different purposes so it's not a matter of X vs Y. Use the Repository because you want to abstract and encapsulate everything storage related and use an ORM to abstract access to any (supported) relational database. The Repository is an architectural pattern, the ORM is an implementation detail of the Repository.

Optimum Ways To Restore A Domain Object From Persistence

By Mike on 6 April 2012

Let's say we have this object (the actual definition is not important)

public class QueueItem
    {    
        public QueueItem(int blogId,string name,Type command,object data)
        {
            if (name == null) throw new ArgumentNullException("name");
            if (command == null) throw new ArgumentNullException("command");
            BlogId = blogId;
            CommandType = command;
            ParamValue = data;
            CommandName = name;
            AddedOn = DateTime.UtcNow;
        }

      
        public Guid Id { get; internal set; }
        public int BlogId { get; private set; }
        public string CommandName { get; set; }
        public Type CommandType { get; private set; }
        public object ParamValue { get; private set; }
        public DateTime AddedOn { get; private set; }
        public DateTime? ExecutedOn { get; private set; }
        public void ExecuteIn(ILifetimeScope ioc)
        {
            throw new NotImplementedException();
        }
    }

This domain object will be handled by a repository

public interface IRepository
{
     void Save(QueueItem item);
     QueueItem Get(Guid id);
}

The repository persists the object, but also has to restore it. And here lies our problem. When implementing the repository, how can we restore the domain object, respecting the encapsulation and without  requiring the object to provide special behaviour for this task.

It turns out that it depends.

Now, when designing the domain object, the design should not care about the persistence needs, it isn't the object's responsibility to know about storage, serializing and deserializing, that's the repository's concern. In this example, when a QueueItem is created, some values are supplied, but the AddedOn property is automatically set by the object. When restoring the object, the repository obviously can't use that constructor, so it needs a way to fill in all the values.

There are several ways, which are most obvious but all have the same flaw: they require that the object change just for this purpose and that's not good.

  1. Having another constructor that has all the values as arguments.
    This solution may work,  but:
    • That constructor is available everywhere and you'd have to specify in comments that that constructor is to be used only for restoring the object. Pretty ugly.
    • If the object has many fields then the constructor needs to accept LOTS of arguments, which is not a pretty sight.
  2. Making all the fields/properties setters public.
    This is probably the worst solution, as it breaks the encapsulation. Don't do it! Ever!
  3. Provide a factory method.
    This is actually the best solution from this group. The domain will keep its encapsulation and the static method won't interfere with the actual usage. Also it provides a very clear intent
    public static QueueItem Restore(Guid id,int blogId /* etc*/) {}

    However is still has the same parameters number problem as the constructor solution, but at least it depends form object to object.

 The good news is there still are other better solutions:

  1. If you're using a document database (like RavenDb) or you're storing the objects in serialized form (I recommend JSON for that) just deserialize it back or let the db do it. But most of the time you won't be using a document database nor you'll be storing the objects in JSON. However it's a good solution, if the conditions are met.
  2. Mapping. Using a mapper (I use Automapper) the domain object is created and its data its copied automatically from a provided source.

These solutions don't require to change anything in the domain object definition so the class can evolve according to the domain needs, ignoring anything persistence related (so the separation of concerns is maintained).

You might have noticed that I didn't include the case when an ORM is used. That's because an ORM is an implementation detail of the repository and the Domain Model is different from the Persistence Model handled by the ORM (I don't consider relevant the cases where those happen to be identical because of a very simplistic domain or a misuse). And being different means you still have to transfer the values from the ORM entities to the domain object.

But what if you can't use any of the good solutions above? No document db and no automapper (I find it hard to believe automapper can't be used almost anywhere but it may be the case). Then the next optimum solution is to use the factory method I've presented before. It's not the best but it's a good compromise. Of course, if the object is very complex perhaps a dedicated factory is a better choice.

The Generic Repository Is An Anti-Pattern

By Mike on 5 March 2012

It seems to me that when you search about repository pattern, you inevitable stumble upon the generic repository, touted as how a repository should be implemented. Too bad that's a fallacy. A repository is a concept to abstract the access to the persistence, that is not to depend on data access implementation details. There is no formula and no rules.

A repository is also the contract used by the rest of the application to save/load objects.  Every application is different and has different needs of accessing the persistence. And yet , many advise you to use a generic repository like this

public interface IRepository<T>
 {
    IEnumerable<T> GetAll();
    T GetByID(int id);   
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
 }

  One of the touted benefits is the DRY (Don't Repeat Yourself) principle. It's good we don't apply the principle when talking, I mean it would be hard not to repeat the same sounds or words. Sadly, for some it seems that every application has the same persistence access needs, because that's the only scenario where a generic repository makes sense.
 
 I'm aware that a Save , Get or Update method are common in a repository but it depends... . Am I dealing with a query repository or a command one? Is it a repository specialized for reading or for updating model? Because a generic repository can't handle those cases. In one repository you might need GetById and GetByTitle with pagination support. In other you might need only a simple Get method. Other repository might deal only with Save/Update a domain entity.
 
 What I'm trying to say is that the design of a repository interface depends too much on what bounded context it applies for, so there isn't a generic form. If you find that things are repeating it might be a sign of poor architecture or that specific application is really suitable for something generic. But that's a specific case, not the rule.
 
 Other offender in regard to generic repositories is the fact that lots of developers just use it to wrap the DAO (Database Access Object) or an underlying ORM (like EF or Nhibernate). Doing so they add only a useless abstraction, pretty much just making the code more complex with no benefits. A DAO makes it easy to work with a database, an ORM makes it easy to access a database as an OOP virtual storage and to eventually abstract the access to a specific database.
 
 But the repository should abstract the whole persistence layer, hiding implementation details like database engine or what DAO or ORM the app is using but also providing a contract that makes sense from the application point of view. The repository serves the application needs, NOT the database needs.
 
 A generic repository serves the dogma because very few applications have a need for a generic contract applicable everywhere and when used just to mask a DAO, it becomes an unnecessary abstraction. These two reasons make the Generic Repository pattern an anti pattern.

Update: A generic repository fits almost naturally as a domain repository, but only as that. To use it anytime you want a repository and especially when dealing with query repos doesn't make sense.

The Repository Pattern Explained

By Mike on 22 February 2012

Made popular by Domain Driven Design, the Repository pattern is one of my favourite design patterns, which I use almost everywhere. What can I say? I like clear separation between the database access and the rest of the application and this is the purpose of the Repository pattern.

Separation of concerns is something you want in every real-life application and one of the most often met culprits when dealing with bad code is the happy mingleling of the database access  all over the place. Of course, this is also encouraged by the database centric approach which still dominates the developers mindset and you need stronger discipline in order to keep the database access isolated.

In DDD, you start with the domain while the database access , in fact the persistence details, is ironed out at a later time. This means you are free to ignore anything persistence related, but  that doesn't mean that there is no persistence. However the persistence is viewed as a collection of objects where domain object are sent to die... sorry to be persisted and to be retrieved from. Note that the important thing is to consider the repository a collection and not to actually implement a collection (for example .net has an ICollection interface, this has nothing to do with a repository). This approach isn't something specific only to DDD, it can be used in any application as it is a design pattern after all.

In a nutshell, the Repository pattern means abstracting the persistence layer, masking it as a collection. This way the application doesn't care about databases and other persistence details, it only deals with the abstraction (which usually is coded as an interface). The Repository also acts as a facade, simplifying the use of the persistence layer. The application just calls the methods of a repository in order to store or retrieve objects.

Even if you don't do DDD, the objects you send or get from the repositories are the business/domain objects and NOT database related objects. This means that the repository implementation has knowledge of the business objects and knows how to recreate them.

Using the Repository pattern doesn't mean there is only one repository in an application. There can be as many as needed, usually a repository deals with a specific context. For example, an application can have an OrdersRepository, an UsersRepository and an AdminRepository. It is good practice to code against an abstraction, so that's why you'll find many examples dealing with defining a repository interface and not a class. Working against an interface makes it easy to have multiple implementations which helps a lot with testing or changing implementation details.

As an example, let's see how we can apply the pattern for a blog engine. When dealing with posts I can use this 

public interface IPostsRepository
    {
        void Save(Post mypost);
        Post Get(int id);
        PaginatedResult<Post> List(int skip,int pageSize);
        PaginatedResult<Post> SearchByTitle(string title,int skip,int pageSize);
    }

    Post is a domain type, it isn't related to a possible Post class that can be defined in the persistence layer if you're using an OR\M. Remember that the Repository talks with the application only using the types that the application knows about. Any class defined for OR\M usage is hidden in the persistence layer as it's simply an implementation detail.
   
    We see methods for saving a post or for retrieving a post. The Save method is smart enough to detect if it's a new post or a modified post. The PaginatedResult<Post>, is a C# generic type, meaning that the List and SearchByTitle methods return a list of Posts with pagination details.
   
    When testing I can mock or stub this interface, without needing to actually implement a real database access. The application will work only with the interface (which will be injected where is needed), without caring about how things will be actually persisted.
   
    There is no rule or format on how to define a repository. You define it according to what you need from it. But most of the time you'll need to Save or to Get objects in different ways.
   
 A word about using transactions with a repository. Since most of the time the Repository is used in a DDD context, I'll refer to this case.  When you need to execute different operations as a unit, there's where the Unit of Work pattern comes into play. And there are discussion if the UoW is part of the Repository of viceversa. However, in DDD ,the repository should save only Aggregate Roots which themselves are a consistent unit. This means you don't need explicit transaction handling, because saving an aggregate root implicitly means that everything belonging to it is persisted as a transaction.