在 MVC 应用程序中从 Model 正确调用数据库? [英] Properly calling the database from Model in an MVC application?

查看:15
本文介绍了在 MVC 应用程序中从 Model 正确调用数据库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个用于学习/实验和小型项目的小型 MVC 框架.我需要找出模型内部的基础知识,因为一个完整的 MVC 框架和 ORM 对于仅仅几个数据库调用来说是多余的.

I'm building a tiny MVC framework for learning/experimenting and small project purposes. I needed to find out the basics of the internals of the Model since a full MVC framework and ORM is overkill for just a few database calls.

Class Model
{
}

使用空类时,我必须在何处调用 new PDO 对象以进行数据库调用?

Using an empty class where would I have to call a new PDO object for database calls?

在模型内部调用查询会是什么样子?

What would calling a query look like inside the Model?

此外,我在哪里可以找到 MVC 的初学者网络/书籍资源(包含大量示例代码)?我听说过很多术语,例如业务逻辑和数据库逻辑.我记得在某处读到您应该将业务逻辑和数据库逻辑分开.我可以稍微理解这个概念,我只是想知道它是什么样子或它们在代码本身中的含义.我很困惑如何将业务逻辑和数据库逻辑分开但仍然在模型内部.

Additionally, where can I find a beginner's web/book resource to MVC (with lots of example code)? I've heard a lot of terms such as business logic and database logic. I remember reading somewhere that you should separate business logic and database logic. I can understand the concept somewhat, I just wonder what it looks like or what they mean in code itself. I'm confused how business logic and database logic should be separated but still be inside the Model.

我主要是在寻找代码/逻辑示例作为答案,可能除了后一段.

I'm mostly looking for code/logic examples as answers, except maybe the latter paragraph.

推荐答案

警告:
此帖子中的信息非常过时.它代表了我对 MVC 模式的理解,因为它是 2 年前的.当我解决它时,它会更新.大概是这个月(2013.09).

该死的!(2017.11).

Warning:
The information in this posts is extremely outdated. It represents my understanding of MVC pattern as it was more then 2 years ago. It will be updated when I get round to it. Probably this month (2013.09).

Damn it! (2017.11).

Model 本身不应包含任何 SQL.曾经.它旨在仅包含域业务逻辑.

Model itself should not contain any SQL. Ever. It is meant to only contain domain business logic.

我建议的方法是将并非严格意义上的业务逻辑"的职责分离成另外两组结构:域对象数据映射器.

The approach i would recommend is to separate the responsibilities, which are not strictly "business logic" into two other other sets of constructs : Domain Objects and Data Mappers.

例如,如果您正在制作博客,那么模型将不会是 Post.相反,模型很可能是 Blog ,并且该模型将处理多个 Domain Objects:Post、Comment、User 和其他对象的多个实例.

For example, if you are making a blog, then the Model will not be Post. Instead most likely the model will be Blog , and this model will deal with multiple Domain Objects: multiple instances of Post, Comment, User and maybe other objects.

在您的模型中,域对象不应该知道如何将自己存储在数据库中.或者甚至注意任何形式的存储的存在.这是Data Mappers 的责任.您应该在模型中做的就是调用 $mapper->store( $comment );.并且数据映射器应该知道如何存储一种特定类型的域对象,并赢得将信息放在哪个表中(通常单个域对象的存储实际上会影响多个表).

In your model, the domain objects should not know how to store themselves in database. Or even be aware of the existence of any form of storage. That is a responsibility of Data Mappers. All you should do in the Model is to call $mapper->store( $comment );. And the data mapper should know how to store one specific type of domain objects, and win which table to put the information ( usually the storage of of single domain object actually affects multiple tables ).

(仅来自文件的相关片段):

(only relevant fragments from files):

  • 我假设您知道如何编写一个好的构造函数 .. 如果您有疑问,请阅读 这篇文章
  • 示例中没有命名空间,但应该是
  • 示例中以 _ 开头的任何内容都是 protected
  • I assume that you know how to write a good constructor .. if you have doubts, read this article
  • nothing is namespaced in example, but it should be
  • anything that begins with _ in example is protected

来自/application/bootstrap.php

/* --- snip --- */

$connection = new PDO( 'sqlite::memory:' );
$model_factory = new ModelFactory( $connection );

$controller = new SomeController( $request , $model_factory );

/* --- snip --- */

$controller->{$action}();

/* --- snip --- */

  • 控制器不需要知道数据库连接.
  • 如果要更改整个应用程序的数据库连接,则需要更改单行
  • 为了改变模型的制作方式,你创建了不同的类来实现与 ModelFactory 相同的接口
  • 来自 /framework/classes/ModelFactory.php

    /* --- snip --- */
    
    class ModelFactory implements ModelBuilderInterface
    {
       /* --- snip --- */
    
       protected function _prepare()
       {
          if ( $this->_object_factory === null  )
          {
             $this->_object_factory = new DomainObjectFactory;
          }
          if ( $this->_mapper_factory === null )
          {
             $this->_mapper_factory = new DataMapperFactory( $this->_connection );
          }
       }
    
       public function build( $name )
       {
          $this->_prepare();
          return new {$name}( $this->_object_mapper , $this->_data_mapper );
       }
    
       /* --- snip --- */
    
    }
    

    • 只有数据映射器会使用数据库,只有映射器工厂需要连接
    • Model 的所有依赖都注入到构造函数中
    • 应用程序中的每个 DataMapper 实例都使用相同的数据库连接,没有 全局状态(视频) 必需.
    • 文件 /application/controllers/SomeController.php

      /* --- snip --- */
      
         public function get_foobar()
         {
            $factory = $this->_model_factory;
            $view = $this->_view;
      
            $foo = $factory->build( 'FooModel' );
            $bar = $factory->build( 'BarModel' );
      
            $bar->set_language( $this->_request->get('lang') );
      
            $view->bind( 'ergo' , $foo );
      
            /* --- snip --- */
      
         }
      
      /* --- snip --- */
      

      • 控制器不知道模型创建细节
      • controller 只负责接线和改变元素的状态
      • 文件 /application/models/FooModel.php

        /* --- snip --- */
        
           public function find_something( $param  , $filter )
           {
              $something = $this->_object_factory('FooBar');
              $mapper = $this->_mapper_factory('FooMapper');
        
              $something->set_type( $param );
              $mapper->use_filter( $filter )->fetch( $something );
        
              return $something;
           }
        
        /* --- snip --- */
        

        • 域对象负责验证给定的参数
        • view 接收并决定如何呈现它
        • mapper 获取对象并将所有必需的信息从存储中放入其中(它不一定是 DB ..它可以从某个文件或外部 REST API 中获取)
        • 我希望这能帮助您理解 DB 逻辑和业务逻辑(实际上也是表示逻辑)之间的分离

          I hope this will help you understand the separation between DB logic and business logic ( and actually , presentation logic too )

          模型永远不应该扩展数据库或 ORM,因为模型不是它们的子集.通过扩展一个类,您声明它具有超类的所有特征,但有少数例外.

          Model should never extend Database or ORM, because Model is not a subset of them. By extending a class, you are declaring that has all the characteristics of the superclass, but with minor exceptions.

          class Duck extends Bird{}
          class ForestDuck extends Duck{}
          // this is ok
          
          class Table extends Database{}
          class Person extends Table{}
          // this is kinda stupid and a bit insulting
          

          除了明显的逻辑问题外,如果您的模型与底层数据库紧密耦合,则会使代码极难测试(谈论 单元测试(视频).

          Besides the obvious logic-issues, if your Model is tightly coupled with underlaying Database, it makes the code extremely hard to test (talking about Unit Testing (video)).

          我个人认为,ORM 在大型项目中是无用的,甚至是有害的.问题源于这样一个事实,即 ORM 试图弥合两种完全不同的解决问题的方法:OOP 和 SQL.

          I personally think, that ORMs are useless and in large project - even harmful. Problem stems from the fact that ORMs are trying to bridge two completely different ways of approaching problems : OOP and SQL.

          如果您使用 ORM 开始项目,那么经过短暂的学习曲线后,您可以非常快速地编写简单的查询.但是当您开始遇到 ORM 的局限性和问题时,您已经完全投入到 ORM 的使用中(甚至可能雇用了新人,他们非常擅长您的选择,但平淡无奇SQL).您最终会遇到每个与数据库相关的新问题都需要越来越多的时间来解决的情况.如果你一直在使用基于 ActiveRecord 模式的 ORM,那么问题会直接影响你的模型.

          If you start project with ORM then, after short learning curve, you are able to write simple queries very fast. But by the time you start hitting the ORM's limitations and problems, you are already completely invested in the use of ORM ( maybe even new people were hired , who were really good at your chosen , but sucked at plain SQL ). You end up in situation where every new DB related issue take more and more time to solve. And if you have been using ORM based on ActiveRecord pattern, then the problems directly influence your Models.

          鲍勃叔叔 将此称为技术债务".

          Uncle Bob calls this "technical debt".

          与主题松散相关

          这篇关于在 MVC 应用程序中从 Model 正确调用数据库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆