Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

ActiveRecordとEctoPartOne

データは、ほとんどのソフトウェアアプリケーションの中核部分です。データベースからのデータのマッピングとクエリは、開発者の生活の中で繰り返されるタスクです。このため、プロセスを理解し、タスクを簡素化する抽象化を使用できることが重要です。

この2つのシリーズの最初の投稿では、ActiveRecord(Ruby)とEcto(Elixir)の比較を紹介します。両方のツールを使用して、開発者がデータベーススキーマを移行およびマッピングする方法を説明します。

そこで、リンゴとオレンジを比較します。 (オリジナル)バットマンとは対照的に、言葉を言う必要がなかったバットガールは、「私はバットマンです」と明示的に述べています。暗黙的、設定より規約、対明示的意図。 1ラウンド。戦え!

ActiveRecord

リリースから10年以上経ちますが、おそらく、ActiveRecordについて聞いたことがあるでしょう。ActiveRecordは、RubyonRailsプロジェクトにデフォルトで付属している有名なORMです。

ActiveRecord はMVCのM(モデル)であり、ビジネスデータとロジックの表現を担当するシステムのレイヤーです。 ActiveRecordは、データがデータベース内の永続ストレージを必要とするビジネスオブジェクトの作成と使用を容易にします。これは、それ自体がオブジェクトリレーショナルマッピングシステムの説明であるActiveRecordパターンの実装です。

Railsで使用されることがほとんど知られていますが、ActiveRecordはスタンドアロンツールとしても使用でき、他のプロジェクトに組み込むことができます。

エクト

ActiveRecordと比較すると、Ectoは非常に新しい(そして現時点ではそれほど有名ではない)ツールです。これはElixirで記述されており、デフォルトでPhoenixプロジェクトに含まれています。

ActiveRecordとは異なり、EctoはORMではありませんが、Elixirを使用してクエリを記述し、データベースと対話できるようにするライブラリです。

エクト は、クエリを記述し、Elixirのデータベースと対話するためのドメイン固有言語です。

設計上、Ectoはスタンドアロンツールであり、さまざまなElixirプロジェクトで使用されており、どのフレームワークにも接続されていません。

リンゴとオレンジを比較していませんか?

はい、そうです! ActiveRecordとEctoは意味的に異なりますが、データベースの移行、データベースマッピング、クエリ、検証などの一般的な機能は、ActiveRecordとEctoの両方でサポートされています。そして、両方のツールを使用して同じ結果を達成できます。 Rubyのバックグラウンドから来たElixirに興味がある人にとって、これは興味深い比較になると思いました。

請求書システム

投稿の残りの部分では、架空の請求書システムがデモンストレーションに使用されます。スーパーヒーローにスーツを販売する店があると想像してみてください。簡単にするために、請求書システムには2つのテーブルのみを用意します。ユーザー および請求書

以下は、これらのテーブルの構造と、フィールドおよびタイプです。

ユーザー

フィールド タイプ
full_name 文字列
メール 文字列
created_at(ActiveRecord)/ insert_at(Ecto) 日時
updated_at 日時

請求書

フィールド タイプ
user_id 整数
payment_method 文字列
payd_at 日時
created_at(ActiveRecord)/ insert_at(Ecto) 日時
updated_at 日時

usersテーブルには4つのフィールドがあります: full_name メール updated_at 使用するツールに依存する4番目のフィールド。 ActiveRecordはcreated_atを作成します Ectoがinserted_atを作成している間のフィールド レコードがデータベースに最初に挿入された瞬間のタイムスタンプを表すフィールド。

2番目のテーブルの名前はinvoices 。 5つのフィールドがあります: user_id payment_method payed_at updated_at そして、usersテーブルと同様に、 created_at またはinserted_at 、使用するツールによって異なります。

ユーザーと請求書の表には、次の関連付けがあります。

  • ユーザーには多くの請求書があります
  • 請求書はユーザーのものです

移行

移行により、開発者は反復プロセスを使用して、時間の経過とともにデータベーススキーマを簡単に進化させることができます。 ActiveRecordとEctoはどちらも、開発者がSQLを直接処理する代わりに、高級言語(それぞれ、RubyとElixir)を使用してデータベーススキーマを移行できるようにします。

ActiveRecordとEctoを使用してユーザーと請求書のテーブルを作成することにより、移行がどのように機能するかを見てみましょう。

ActiveRecord:ユーザーテーブルの作成

移行

class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :full_name, null: false
      t.string :email, index: {unique: true}, null: false
      t.timestamps
    end
  end
end

ActiveRecordの移行により、create_tableを使用してテーブルを作成できます 方法。 created_at およびupdated_at フィールドは移行ファイルで定義されていません。t.timestampsを使用します。 ActiveRecordをトリガーして両方を作成します。

作成されたテーブル構造

CreateUsersを実行した後 移行の場合、作成されるテーブルは次の構造になります。

   Column   |            Type             | Nullable |              Default
------------+-----------------------------+----------+-----------------------------------
 id         | bigint                      | not null | nextval('users_id_seq'::regclass)
 full_name  | character varying           | not null |
 email      | character varying           | not null |
 created_at | timestamp without time zone | not null |
 updated_at | timestamp without time zone | not null |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "index_users_on_email" UNIQUE, btree (email)

移行は、電子メールフィールドの一意のインデックスの作成にも関与します。オプションindex: {unique: true} 電子メールフィールド定義に渡されます。これが、テーブルに"index_users_on_email" UNIQUE, btree (email)がリストされている理由です。 その構造の一部としてのインデックス。

Ecto:ユーザーテーブルの作成

移行

defmodule Financex.Repo.Migrations.CreateUsers do
  use Ecto.Migration
 
  def change do
    create table(:users) do
      add :full_name, :string, null: false
      add :email, :string, null: false
      timestamps()
    end
 
    create index(:users, [:email], unique: true)
  end
end

Ecto移行は、関数create()を組み合わせたものです およびtable() ユーザーテーブルを作成します。 Ecto移行ファイルは、同等のActiveRecordと非常によく似ています。 ActiveRecordのタイムスタンプフィールド(created_at およびupdated_at )はt.timestampsによって作成されます Ectoのタイムスタンプフィールド(inserted_at およびupdated_at )はtimestamps()によって作成されます 機能。

インデックスの作成方法については、両方のツールにわずかな違いがあります。 ActiveRecordでは、インデックスは作成されるフィールドのオプションとして定義されます。 Ectoは、関数create()の組み合わせを使用します およびindex() それを達成するために、組み合わせを使用してテーブル自体を作成する方法と一致します。

作成されたテーブル構造

   Column    |            Type             | Nullable |              Default
-------------+-----------------------------+----------+-----------------------------------
 id          | bigint                      | not null | nextval('users_id_seq'::regclass)
 full_name   | character varying(255)      | not null |
 email       | character varying(255)      | not null |
 inserted_at | timestamp without time zone | not null |
 updated_at  | timestamp without time zone | not null |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "users_email_index" UNIQUE, btree (email)

Financex.Repo.Migrations.CreateUsersの実行時に作成されたテーブル 移行の構造は、ActiveRecordを使用して作成されたテーブルと同じです。

ActiveRecord:invoicesの作成 表

移行

class CreateInvoices < ActiveRecord::Migration[5.2]
  def change
    create_table :invoices do |t|
      t.references :user
      t.string :payment_method
      t.datetime :paid_at
      t.timestamps
    end
  end
end

この移行には、t.referencesが含まれます メソッド、それは前のものには存在しませんでした。これは、usersテーブルへの参照を作成するために使用されます。前述のように、ユーザーには多くの請求書があり、請求書はユーザーに属しています。 t.references メソッドはuser_idを作成します 請求書テーブルの列にその参照を保持します。

作成されたテーブル構造

     Column     |            Type             | Nullable |               Default
----------------+-----------------------------+----------+--------------------------------------
 id             | bigint                      | not null | nextval('invoices_id_seq'::regclass)
 user_id        | bigint                      |          |
 payment_method | character varying           |          |
 paid_at        | timestamp without time zone |          |
 created_at     | timestamp without time zone | not null |
 updated_at     | timestamp without time zone | not null |
Indexes:
    "invoices_pkey" PRIMARY KEY, btree (id)
    "index_invoices_on_user_id" btree (user_id)

作成されたテーブルは、以前に作成されたテーブルと同じパターンに従います。唯一の違いは、追加のインデックス(index_invoices_on_user_id )、t.referencesのときにActiveRecordが自動的に追加します メソッドが使用されます。

Ecto:invoicesの作成 表

移行

defmodule Financex.Repo.Migrations.CreateInvoices do
  use Ecto.Migration
 
  def change do
    create table(:invoices) do
      add :user_id, references(:users)
      add :payment_method, :string
      add :paid_at, :utc_datetime
      timestamps()
    end
 
    create index(:invoices, [:user_id])
  end
end

Ectoは、references()を使用して、データベース参照の作成もサポートしています。 関数。列名を推測するActiveRecordとは異なり、Ectoでは開発者がuser_idを明示的に定義する必要があります。 列名。 references() 関数では、開発者が参照が指しているテーブル(この例ではusersテーブル)を明示的に定義する必要もあります。

作成されたテーブル構造

     Column     |            Type             | Nullable |               Default
----------------+-----------------------------+----------+--------------------------------------
 id             | bigint                      | not null | nextval('invoices_id_seq'::regclass)
 user_id        | bigint                      |          |
 payment_method | character varying(255)      |          |
 paid_at        | timestamp without time zone |          |
 inserted_at    | timestamp without time zone | not null |
 updated_at     | timestamp without time zone | not null |

Indexes:
    "invoices_pkey" PRIMARY KEY, btree (id)
    "invoices_user_id_index" btree (user_id)
Foreign-key constraints:
    "invoices_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)

どちらの移行も非常に似ています。 referencesの方法に関しては 機能は処理されますが、いくつかの違いがあります:

  1. Ectoは、user_idへの外部キー制約を作成します フィールド("invoices_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id) )、ユーザーと請求書テーブル間の参照整合性を維持します。

  2. ActiveRecordは、user_idのインデックスを自動的に作成します 桁。 Ectoは、開発者がそれについて明示することを要求します。これが、移行にcreate index(:invoices, [:user_id])がある理由です。 ステートメント。

ActiveRecord:データマッピングと関連付け

ActiveRecordは、「設定より規約」のモットーで知られています。デフォルトでは、モデルクラス名を使用してデータベーステーブル名を推測します。 Userという名前のクラス 、デフォルトでは、usersを使用します ソースとしてのテーブル。 ActiveRecordは、テーブルのすべての列をインスタンス属性としてマップします。開発者は、テーブル間の関連付けを定義するだけで済みます。これらは、関連するクラスとテーブルを推測するためにActiveRecordによっても使用されます。

ActiveRecordを使用してユーザーと請求書のテーブルがどのようにマッピングされているかを見てみましょう:

ユーザー

class User < ApplicationRecord
  has_many :invoices
end

請求書

class Invoice < ApplicationRecord
  belongs_to :user
end

Ecto:データマッピングと関連付け

一方、Ectoでは、開発者がデータソースとそのフィールドについて明示的にする必要があります。 Ectoにも同様のhas_manyがありますが およびbelongs_to 機能については、開発者が関連するテーブルと、そのテーブルスキーマを処理するために使用されるスキーマモジュールについて明示的にする必要もあります。

Ectoがユーザーと請求書の表をマッピングする方法は次のとおりです。

ユーザー

defmodule Financex.Accounts.User do
  use Ecto.Schema
 
  schema "users" do
    field :full_name, :string
    field :email, :string
    has_many :invoices, Financex.Accounts.Invoice
    timestamps()
  end
end

請求書

defmodule Financex.Accounts.Invoice do
  use Ecto.Schema
 
  schema "invoices" do
    field :payment_method, :string
    field :paid_at, :utc_datetime
    belongs_to :user, Financex.Accounts.User
    timestamps()
  end
end

まとめ

この投稿では、瞬きすることなくリンゴとオレンジを比較しました。 ActiveRecordとEctoがデータベースの移行とマッピングをどのように処理するかを比較しました。暗黙のスリントなオリジナルのバットガールと明示的な「私はバットマン」のバットマンの戦い。

「設定より規約」のおかげで、ActiveRecordを使用すると、通常、書き込みが少なくて済みます。 Ectoは反対の方向に進み、開発者は自分たちの意図についてより明確にする必要があります。一般的に「コードが少ない」方が優れていることを除けば、ActiveRecordにはいくつかの最適なデフォルトがあり、開発者はすべてについて決定を下す必要がなく、基礎となるすべての構成を理解する必要もありません。初心者の場合、ActiveRecordは、その標準に厳密に従う限り、デフォルトで「十分に適切な」決定を行うため、より適切なソリューションです。

Ectoの明示的な側面により、コードの動作を読みやすく理解しやすくなりますが、開発者はデータベースのプロパティと使用可能な機能についてさらに理解する必要があります。 Ectoを一見面倒に見えるかもしれないのは、その長所の1つです。 ActiveRecordとEctoの両方の世界での私の個人的な経験に基づいて、Ectoの明示性は、ActiveRecordを使用するプロジェクトで一般的な「舞台裏」の影響と不確実性を取り除きます。開発者がコードで読み取るのは、アプリケーションで発生することであり、暗黙の動作はありません。

数週間後の2番目のブログ、2部構成の「ActiveRecordvs Ecto」シリーズでは、ActiveRecordとEctoの両方でクエリと検証がどのように機能するかについて説明します。

この記事についてのご意見をお聞かせください。常に新しいトピックを探しています。詳しく知りたいテーマがある場合は、遠慮なく@AppSignalまでお知らせください。


  1. ER図の最小化

    問題の説明 ERダイアグラムは、さまざまなテーブルとそれらの間の関係を図で表したものです。データベースの数を減らすことができるER図。 1対1のカーディナリティ 以下の図を1対1のカーディナリティで考えてみましょう- 上記のER図は3つのエンティティを表しています- 従業員エンティティには、emp_nameという2つの属性があります。 emp_idが主キーです 会社エンティティには、cmp_nameという2つの属性があります。 cmp_idが主キーです 作業エンティティの主キーはemp_idまたはcmp_idにすることができます 3つのテーブルを1つに結合することはできず、Wo

  2. 修正:Err_Connection_Closed

    Google Chromeは、最新の最も人気のあるインターネットブラウザの1つであり、ハイエンドPCに優れたパフォーマンスを提供します。弱いPCでもうまく機能しますが、RAMの消費量は、RAMが3 GB未満のコンピューター、特にインスタンスに開いているタブがたくさんある場合に大きな問題になります。 ブラウザはGoogleによって絶えず更新されており、Googleアカウントを使用するときに同期されたエクスペリエンスを提供するように機能するため、すべてのデバイスが同じ履歴を共有します。この特定のエラーを見てみましょう。 ChromeのERR_CONNECTION_CLOSED このエラーは、