What exactly is the difference between a data mapper and a repository?

亡梦爱人 提交于 2019-11-30 00:26:20

Suppose your application manages Person objects, with each instance having name, age and jobTitle properties.

You would like to persist such objects, retrieve then from the persistence medium and maybe update (say, on their birthday, incrementing the date) or delete. These tasks are usually referred to as CRUD, from Create, Read, Update and Delete.

It is preferable to decouple your "business" logic from the logic that deals with the persistence of Person objects. This allows you to change the persistence logic (e.g. going from a DB to a distributed file system) without affecting your business logic.

You do this by encapsulating all persistence logic behind a Repository. A hypothetical PersonRepository (or Repository<Person>) would allow you to write code like this:

Person johnDoe = personRepository.get(p=> p.name == "John Doe"); johnDoe.jobTitle = "IT Specialist"; personRepository.update(johnDoe);

This is just business logic and doesn't care about how and where the object is stored.

On the other side of the Repository, you use both a DataMapper and something that translates queries from the functional description (p=> p.name == "John Doe" to something that the persistence layer understands).

Your persistence layer can be a DB, in which case the DataMapper converts a Person object to and from a row in a PersonsTable. The query translator then converts the functional query into SELECT * FROM PersonsTable WHERE name == "John Doe".

Another persistence layer can be a file system, or another DB format that chooses to store Person objects in two tables, PersonAge and PersonJobTitle.

In the latter case, the DataMapper is tasked with converting the johnDoe object into 2 rows: one for the PersonAge table and one for the PersonJobTitle table. The query logic then needs to convert the functional query into a join on the two tables. Finally, the DataMapper needs to know how to construct a Person object from the query's result.

In large, complex systems, you want to use small components that do small, clearly defined things, that can be developed and tested independently:

  • The business logic deals with a Repository when it wants to read or persist objects, and doesn't care how that is implemented.
  • The Repository deals with a DataMapper when it wants to read/write an object in a particular persistence medium.
  • For querying, the Repository relies on a schema provided by the DataMapper (e.g. the jobTitle value is found in the JobTitle column in the PersonTable table) but not on any implementation of a mapper.
  • For DB persistence, the DataMapper relies on a DB layer, that shield it from the Oracle/Sybase/MSSQL/OtherProvider details.

The patterns don't "differ", they just expose different basic features.

I realize that this answer is kind of late, but it may help someone in the future that stumbles upon this same question and finds that the available answer(s) do not quite answer the question (which I felt when I first came across this question).

After having read PoEAA (Martin Fowler), I too was having trouble identifying the difference between a data mapper and a repository.

This is what I've found that the 2 concepts ultimately boil down to:

  • a Repository acts like a collection of domain objects, with powerful querying capabilities (Evans, DDD)
  • a DataMapper "moves data between objects and a database while keeping them independent of each other and the mapper itself" (Fowler, PoEAA)

Repositories are a generic concept and don't necessarily have to store anything to a database, its main function is to provide collection like (query-enabled) access to domain objects (whether they are gotten from a database is besides the point). Repositories may (and often will) contain DataMappers themselves.

DataMappers serve as the middle layer between domain objects and a database, allowing them to evolve independently without any one depending on the other. Datamappers might have "find" or query functionality, but that is not really their main function. The more you find that you are using elaborate query logic in your DataMappers, the more you want to start thinking about decoupling that query logic into a repository while leaving your DataMappers to serve their main function, mapping domain objects to the database and vice versa.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!