Where are the boundaries between class responsibility zones when using the Data Mapper pattern?

If I correctly understand the logic of the pattern, there are at least three such classes: the mapper itself, the object of the object layer and the repository . And if everything is clear with the division of basic (CRUD) tasks, it is not clear which class should be responsible for the search .

Suppose there is a find () method in the mapper, which by identifier finds the required entry and returns the finished object of the object layer. This is in theory, and in practice in real systems, the search conditions are much more: the equipment model can be searched not only by the identifier, but also (for example) by manufacturer, category, cost, production date.

The situation is much more complicated if the attributes in the object of the object layer differ in their spelling from the field names in the database (for example, the producerId in the code and the producer_id in the database).

Well, the situation becomes even more complicated if there are several related objects in the system and inheritance with a single table is used . Mapper quietly takes the class name from the database with other data and generates this or that object.

So, about the search. So, you need to create another class that will be responsible for the search? And if the mapper returns one of three possible objects, then there should be three such classes already?

Podpnite, pozhalista in the right direction.

  • one
    DataMapper simply maps data to objects. You probably have a problem "how to organize the data access layer, and then so many different patterns." - vitidev pm
  • @vitidev, DataMapper, encapsulates the DomainObject on the repository. And this is a two-way mapping. As a consequence, the place of implementation of methods for selecting objects from the storage is of fundamental importance. - Dmitriy Simushev pm
  • @DmitriySimushev and what did I say? - vitidev

1 answer 1

I advise first of all to look towards ready-made solutions: Doctrine for PHP and Hibernate for Java , also for reading: M. Fowler's "Corporate Application Templates" is a classic work, the section on object-relational mapping patterns is all yours.

Now, of course, in the short answer I will not be able to convey to you in a nutshell the contents of the whole section of the book and the conclusions from familiarizing with the Doctrine source codes, but I will try to "push" :)

First, the search results are given to the client either by Mapper or Repository. Who exactly depends on the implementation and point of view, there is no single right answer. There is no need to create a separate class that will be responsible only for the search, but sometimes it is necessary to select a separate interface (for example, ProductFinder ) that will be related to the domain package and will be implemented in the data access package classes (in your mappers). Those. domain classes will be aware of the search interface, but will not depend on the specific implementation.

Secondly, in mappers, you can define, besides find() methods of the findBy series findBy(array $criteria) , which can solve particular search problems. The problem with the discrepancy between the names of columns and fields - mappers should be solved based on their configuration or based on metadata. One of the tasks of the mapper is to make your objects independent of the storage structure. By the way, to fully implement the findBy methods, etc., you need to implement the Specification pattern in one form or another. By the way, the quotation from Fowler (not exact): "the implementation of the Repository and Specification patterns often contains a significant part of the implementation of the object database ", which in general should once again be prompted to take a ready (and most importantly proven) solution.

About inheritance: the transformer must know which entity on which table it is transforming. In general, again I advise you to see how this problem is solved in the same Hibernate .

UPD

Do I understand correctly that the date mapper assumes one entity = one table (this is even in the answer, in the last paragraph you can see)?

Wrong.

This is a complex question and it’s worth figuring out the theoretical base not the last paragraph of my answer (in which, as I mentioned already, I can’t fully cover the topic with all my desire), but at least the book of M. Fowler mentioned in the first paragraph ( which any useful to read any developer).

In short, the Data Mapper is a special case of the Mapper pattern. Motivation for its use: make business logic as independent as possible from the data storage structure at the data source .

Pay attention to the phrase Data Source ( Data Source , if you wish). If you think of an abstract concept of a data source , you can see that the table in the database is just a special case of it. But it is worth noting that this particular case covers 95% of the tasks of developers of modern applications, so most of the developers of libraries and packages, focuses on it. But. Again, the table in the database is just a special case of the data source. Accordingly, you can write a gateway to another data source - for example, you can consider the result of a query , as a data source - with which your converter (mapper) will work.

By the way, I don’t know how it fits your case, but you can create a view in the database and work with it as a table if you need to read data (with a record, most likely, with any particularly simple or general solution, it will not work for situations when one entity is assembled from multiple tables — you will have to either prescribe in each mapper the logic of converting fields into data and sending the corresponding data to your data source for writing, or organize the cunning transformation logic based on metadata). Plus, I can not help but notice that if one entity does not map to one table, then it may still be a reason to consider it as a composition of other entities, each of which maps to its table and has its own interface and logic, and the general entity will be a certain " orchestrator "to work with its members, providing a higher level interface.

Once again I advise: buy-download and read Fowler, if you want to really understand the question. From fragments of short answers to SO, you will not form a beautiful structured shelf of consistent knowledge on such a complex issue. Moreover, (judging by the question "mapper = table?" , This is already happening to some extent), you may have a correct part of these passages in some parts, but not a whole picture of understanding on this (it is worth noting a very important for any developer enterprise-oriented issue.

Here, as a bonus, some links on the Doctrine will help you:

https://stackoverflow.com/questions/5741318/mapping-two-tables-to-one-entity-in-doctrine2 https://stackoverflow.com/questions/16037626/symfony2-map-entity-to-different-tables

  • In the second paragraph, you talk about Doctrine, and in the last, about Hibernate. Nesostikovochka. - Dmitriy Simushev pm
  • In the answer text, both Doctrine and Hibernate are provided as examples of proven solutions that I advise you to look at. Where is the "inconsistency"? If something is not clear - ask, specify, if possible I will add the answer. - Igor Karpenko
  • Inconsistency in the expressions that you use. The phrase " In general, again, I advise, " as if hinting that Hibernate is already discussed above. But no. Although I, of course, am finding fault =) - Dmitriy Simushev
  • in the first paragraph advised, t.ch. it was really going) considering that you did not indicate in what language you are interested in implementation, I considered that it would be useful to cite several examples from different languages. and the general principles can be peeped there and there. - Igor Karpenko
  • I read, I look at source codes and the first that is evident, - a projection of entities on tables. Do I understand correctly that the date mapper assumes one entity = one table (this is even in the answer, in the last paragraph you can see)? So be it. OK. But what to do if in a DB one entity is spread over several tables? Well, I do not like EAV, so I have to share the data. Doctrine’s $ tableName is alarming in this respect. - Denis Khvorostin