PHP MVC:数据映射器模式:类设计

我有一个带有域对象和数据映射器的Web MVC应用程序。 数据映射器的类方法包含所有数据库查询逻辑。 我试图避免镜像任何数据库结构,因此,在构建sql语句时实现最大的灵活性。 所以,原则上,我试图不使用任何ORM或ActiveRecord结构/模式AT ALL。

让我给你一个例子:通常,我可以有一个抽象类AbstractDataMapper继承所有特定的数据映射类 - 就像UserDataMapper类。 然后,我可以定义一个findById()的方法AbstractDataMapper ,抓取特定表的记录-样users -通过给定的id值,例如用户ID。 但是这意味着我总是从单个表中获取记录,而没有可能使用任何左连接从一些其他表中获取与给定的id - 用户标识相对应的其他一些细节。

所以,我的问题是:在这些条件下 - 我自己有义务应该实现抽象数据映射器类,还是每个数据映射器类都应该包含它自己的完全“专有”数据访问层实现?

我希望我能清楚地表达我的想法。 请告诉我,如果我有点不清楚或者您有任何问题。

非常感谢您的时间和耐心。


如果我明白你的观点......

让所有具体的映射器从一个普通的类继承SQL有几个问题,你已经错过了:

  • 域对象中的参数名称取决于列的名称
  • 在mappers中有一个“提取方法”,它没有相应的表格
  • 您仍然拥有超类预期的配置(表名)
  • 数据库模式必须具有所有PRIMARY KEY列的id作为名称
  • 现在,我要试着解开其中的每一个。

    参数和列名称

    要创建一个共享的findById()方法,唯一实用的方法是围绕如下内容构建它:

    "SELECT * FROM {$this->tableName} WHERE id = :id"
    

    主要问题实际上是通配符*符号。

    使用数据映射器填充实体有两种主要方法:使用setter或使用反射。 在这两种情况下,参数/设置器的“名称”都是由您选择的列隐含的。

    在普通查询中,您可以执行诸如SELECT name AS fullName FROM ... ,这可让您使用查询重新命名字段。 但采用“统一方法”,没有好的选择。

    每个映射器都可以通过id获取数据?

    所以,事情是,除非你有一个mapper-per-table结构(在这种情况下,一个活动记录开始看起来像实用选项),那么最终你的映射器只会有很少(非常常见的)“边缘情况”场景:

  • 仅用于保存数据
  • 处理收集而不是单个实体
  • 汇总来自多个表格的数据
  • 与具有组合键的表一起工作
  • 它实际上不是一个表,而是一个SQL视图
  • ...或上述的组合
  • 你最初的想法在小规模项目中可以很好地工作(一个或两个映射器是一个“边缘案例”)。 但是对于一个大型项目, findById()的使用将成为例外而非常态。

    独立父母吗?

    要在超类中实际获取此findById()方法,您需要一种方法将表名与它通信。 这意味着,你在类定义中有类似protected $tableName东西。

    您可以通过在抽象映射器类中使用abstract function getTableName()来减轻它的影响,该类在实现时返回全局常量的值。

    但是,当您的映射器需要使用多个表时会发生什么情况。

    这似乎是一种代码味道,因为信息实际上跨越了两个界限(缺乏更好的单词)。 当此代码中断时,将在超类中显示SQL的错误,这不是错误源自的地方(尤其是,如果使用常量)。

    命名主键

    这是一个更有争议的观点:)

    据我所知,调用所有主要列id的做法来自各种ORM。 这招致的惩罚仅适用于可读性(和代码维护)。 考虑这两个查询:

    SELECT ar.id, ac.id 
      FROM Articles AS ar LEFT JOIN 
           Accounts AS ac ON ac.id = ar.account_id 
     WHERE ar.status = 'published'
    
    SELECT ar.article_id, ac.account_id 
      FROM Articles AS ar LEFT JOIN 
           Accounts AS ac USING(account_id)
     WHERE ar.status = 'published'
    

    随着数据库模式的增长和查询变得越来越复杂,实际上越来越难以追踪,在什么情况下“id”代表什么。

    我的建议是尝试使用相同的名称作为列,当它是主要的时候它是一个外键(在可能的情况下,因为在某些情况下,像“关闭表,它是不可行的)基本上,所有存储ID相同的类型,应该有相同的名称。

    作为一个小小的奖励,你会得到USING()语法糖。

    TL; DR

    馊主意。 你基本上打破了LSP。

    链接地址: http://www.djcxy.com/p/56223.html

    上一篇: PHP MVC: Data Mapper pattern: class design

    下一篇: How to load a one