tag:crieit.net,2005:https://crieit.net/tags/ORM/feed
「ORM」の記事 - Crieit
Crieitでタグ「ORM」に投稿された最近の記事
2022-06-09T23:58:40+09:00
https://crieit.net/tags/ORM/feed
tag:crieit.net,2005:PublicArticle/18211
2022-06-09T23:58:40+09:00
2022-06-09T23:58:40+09:00
https://crieit.net/posts/eloquent-use-db-raw-a-facade-root-has-not-been-set-error-20220610
Eloquent 単独で COUNT(*) を使用したいが DB:raw() を使用すると A facade root has not been set. エラーになる
<h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2>
<p>Eloquent 単独利用しているプログラムの中で COUNT(*) を使用したくなったのでその方法をメモ。</p>
<p>単純に件数をカウントしてその数値を使いたいだけであれば</p>
<pre><code class="php">$data_count = $dbConnect->table('hoge')
->count();
</code></pre>
<p>で済ませることができます。が、今回はサブクエリとして使用した方がコード的にすっきりしそうな状況でした。</p>
<p>先の方法ではコード上は関連性のない別のクエリをもう1つ記述しなければならないので如何なものかと思い……。</p>
<h2 id="調査"><a href="#%E8%AA%BF%E6%9F%BB">調査</a></h2>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://awesome-programmer.hateblo.jp/entry/2019/07/03/162835">LaravelのEloquentで集計関数Count()などを使うとき - バックエンドとフロントエンドを行き来するWEBプログラマ―のメモ帳</a></li>
</ul>
<p>検索したところ、 SQL で <code>COUNT(*)</code> を使用する場合は <code>DB:raw()</code> を使うとのこと。</p>
<p>ただし、 Laravel の中ならばいざ知らず今回は Eloquent 単独使用なので、 <code>DB</code> なるクラスはどこから来るのか……となってしまいました。しかも <code>::raw()</code> は static メソッドですし。</p>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://readouble.com/laravel/8.x/ja/queries.html">データベース:クエリビルダ 8.x Laravel</a></li>
</ul>
<p>引き続き検索すると、 <code>DB</code> はファサードでした。</p>
<p>しかし、 Laravel 公式のサンプルのように</p>
<pre><code class="php">use Illuminate\Support\Facades\DB;
</code></pre>
<p>を追加すると、</p>
<blockquote>
<p>A facade root has not been set.</p>
</blockquote>
<p>というエラーが発生して怒られてしまいます。</p>
<p>通常の Laravel 内で使用する場合はインスタンスとの紐付けが上手く行われますが、今回は Eloquent のみの単体使用なのでこのパターンではできそうにないように見受けられました (できたとしても素直に Laravel を使った方が早そう)。</p>
<p>最終的には</p>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/s-higuma/items/ab8fa110b13301d0c959">Eloquentを単体で導入している時にDBファサードを使用する方法 - Qiita</a></li>
</ul>
<p>この記事の方法で</p>
<pre><code class="php">use \Illuminate\Database\Capsule\Manager as DB;
</code></pre>
<p>を <code>DB::raw()</code> を使うクラスのファイルの中で再度読み込ませる (別のファイルでDB接続用のインスタンスを生成していて、それを DI していたので今回は「再度読み込ませる」という表現) ことで乗り越えることができました。</p>
<h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2>
<h3 id="count()"><a href="#count%28%29">count()</a></h3>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/zaburo/items/d665804f8ea850502c64">Laravelでの基本的なリレーションシップもしくはJOIN - Qiita</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://www.84kure.com/blog/2017/07/12/laravel-eloquent%E3%81%A7%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AE%E6%B3%A8%E6%84%8F/">[Laravel] Eloquentでカウントするときの注意 – 端くれプログラマの備忘録</a></li>
</ul>
<h3 id="DB::raw()"><a href="#DB%3A%3Araw%28%29">DB::raw()</a></h3>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://awesome-programmer.hateblo.jp/entry/2019/07/03/162835">LaravelのEloquentで集計関数Count()などを使うとき - バックエンドとフロントエンドを行き来するWEBプログラマ―のメモ帳</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://readouble.com/laravel/8.x/ja/queries.html">データベース:クエリビルダ 8.x Laravel</a></li>
</ul>
<h3 id="A facade root has not been set. エラー"><a href="#A+facade+root+has+not+been+set.+%E3%82%A8%E3%83%A9%E3%83%BC">A facade root has not been set. エラー</a></h3>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://re-engines.com/2020/05/11/laravel-facade/">LaravelのFacade(ファサード)とは? 何気なく使用していた裏側の仕組みを解説! | RE:ENGINES</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://www.wakuwakubank.com/posts/453-laravel-sql-basic/">Laravel|DBデータ操作(DBファサード, クエリビルダ, Eloquent) - わくわくBank</a> (バージョン古い)</li>
<li><a target="_blank" rel="nofollow noopener" href="https://matchingood-engineer.hatenablog.com/">エンジニアブログ</a> (バージョン古い)</li>
<li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/22925451/how-can-i-query-raw-via-eloquent">php - How can I query raw via Eloquent? - Stack Overflow</a> (バージョン古い)</li>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/s-higuma/items/ab8fa110b13301d0c959">Eloquentを単体で導入している時にDBファサードを使用する方法 - Qiita</a></li>
</ul>
arm-band
tag:crieit.net,2005:PublicArticle/18193
2022-05-19T23:50:29+09:00
2022-05-19T23:50:29+09:00
https://crieit.net/posts/eloquent-connect-multiple-db-20220520
Eloquent で複数DBに接続する
<p>単独の Eloquent を利用して異なるデータソースにアクセスしてみたのでメモしておきます。</p>
<h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2>
<pre><code class="php"><?php
declare(strict_types=1);
use Illuminate\Database\Capsule\Manager;
class DBConnection
{
private $db;
public function __construct()
{
$this->db = new Manager;
// default
$this->db->addConnection([
'driver' => 'mysql',
'host' => $_ENV['MYSQL1_HOST'],
'database' => $_ENV['MYSQL1_DBNAME'],
'username' => $_ENV['MYSQL1_USER'],
'password' => $_ENV['MYSQL1_PASSWORD'],
'charset' => 'utf8',
]);
// second
$this->db->addConnection([
'driver' => 'mysql',
'host' => $_ENV['MYSQL2_HOST'],
'database' => $_ENV['MYSQL2_DBNAME'],
'username' => $_ENV['MYSQL2_USER'],
'password' => $_ENV['MYSQL2_PASSWORD'],
'charset' => 'utf8',
],
'second'); // addConnection() メソッドの第二引数に接続名を指定する (1つ目はなしだと default になる)
$this->db->setAsGlobal();
$this->db->bootEloquent();
}
// 略
}
</code></pre>
<p>肝はコメントにも記した通り <code>Manager</code>クラス の <code>addConnection()</code>メソッド について、第二引数に接続名を指定することです (1つ目はなしだと <code>default</code> になり、後で使用する分にも指定は不要) 。</p>
<p>あ、しれっと書いていますが <code>dotenv</code> を使用した想定です。</p>
<pre><code class="php"><br />$db = new DBConnection();
$secondDBrows = $db->connection('second')->table('hoge_db')
->where( /* 略 */ )
->select( /* 略 */ )
->get();
</code></pre>
<p>こちらもしれっと書いていますがイメージとしては先程のDB接続用クラス <code>DBConnection</code> をインスタンス化して、その中から <code>connection()</code>メソッド で引数に先程指定した接続名を記述することで二つ目の接続を利用してDBにアクセスできる、ということです。</p>
<p>これで意図したことを実装することができました。</p>
<h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://blog.bagooon.com/?p=1492">Laravelを使わず、直接PHPからEloquentを使用し、かつ複数のDBに接続する方法。</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://technoledge.net/composer-eloquent-illuminate-database/">LaravelのORM「Eloquent」を単体で使ってスクラッチ開発する | テクナレジ</a></li>
</ul>
arm-band
tag:crieit.net,2005:PublicArticle/18191
2022-05-18T00:03:50+09:00
2022-05-18T00:03:50+09:00
https://crieit.net/posts/eloquent-multiple-where-condition-closure-20220518
Eloquent で複合条件の抽出をする
<p>Eloquent を実践的に使い始めたばかりなので初歩的なところですが、複合条件を組み立てるところについてメモ。</p>
<h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2>
<p>やりたいこととしては、 <code>WHERE A AND B AND (C OR D)</code> という条件。</p>
<pre><code class="php">$departName = [
'総務部',
'営業部',
];
$dataRows = $dbConnect->table('hoge_db')
->where(
[
['user_id', '>', 23],
['age', '<', 42],
]
)
->where(function($query) use ($departName) {
$query->orWhere('depart_name', '=', $departName[0])
->orWhere('depart_name', '=', $departName[1]);
})
->select(
'fuga_db.name',
'fuga_db.attribute',
'fuga_db.parameter'
)
->join('fuga_db', 'hoge_db.user_id', '=', 'fuga_db.employee_id')
->get();
</code></pre>
<p><code>$dbConnect</code> にDB接続情報が入ったインスタンスがあるという前提ですが、イメージとしてこのようなコードです。</p>
<p>肝は以下。</p>
<ul>
<li><code>OR</code> 条件の括弧の中身を <code>where()</code>メソッド の中にクロージャとして無名関数で記述する。</li>
<li>関数の引数はクエリ。そこに <code>orWhere()</code>メソッド を足していく。</li>
<li>クロージャの外部の変数はスコープの関係で Undefined Variable になってしまうので <code>use</code>句 でクロージャ内に持ち込む</li>
</ul>
<p>これで意図した挙動になることを確認しました。</p>
<h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/Hwoa/items/542456b63e51895f9a55">Laravel5で「.. or ...) and (..」みたいな複雑な条件を書く - Qiita</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/mitashun/items/7b1a6c4bb44acd08472e">【Laravel】EloquentでOR検索する方法 - Qiita</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://umebius.com/laravel/querybuilder%E3%81%AB%E3%82%88%E3%82%8Band%E6%A4%9C%E7%B4%A2%E3%81%A8or%E6%A4%9C%E7%B4%A2%E3%81%AE%E8%A4%87%E5%90%88/">Eloquent\/QueryBuilderによるAnd検索とOr検索の複合 - Laravel5開発</a></li>
</ul>
arm-band
tag:crieit.net,2005:PublicArticle/14502
2018-08-10T23:09:11+09:00
2019-05-03T09:19:45+09:00
https://crieit.net/posts/Nuxt-js-Express-ORM
Nuxt.js+Expressでとにかく簡単にORM
<p>Nuxt.jsとExpressを使ってアプリケーションを作るとなると、やはりMySQL等を使うためにORMのライブラリが欲しくなります。Node.jsにはSequelizeというORMのライブラリがあり、それを使って簡単にデータベースを使うことが可能です。</p>
<h2 id="趣旨"><a href="#%E8%B6%A3%E6%97%A8">趣旨</a></h2>
<p>Sequelizeの使い方の説明は他のサイトの記事などがもっと参考になります。ただ、とりあえずすぐ簡単に使う、という趣旨の記事があまりなさそうだったのでそのあたりに重点を置いて書いてみます。</p>
<p>ちなみに下記で作ったプロジェクトの続きとして作っています。<br />
<a href="https://crieit.net/posts/Nuxt-Express">Nuxt+Expressのプロジェクト作成で良さそうなのは?</a></p>
<h2 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h2>
<p>インストールはマニュアル通りです。npmを使う場合はマニュアルを見てください。</p>
<p><a target="_blank" rel="nofollow noopener" href="http://docs.sequelizejs.com/manual/installation/getting-started.html">Installation | Sequelize | The node.js ORM for PostgreSQL, MySQL, SQLite and MSSQL</a></p>
<pre><code class="sh">// Using Yarn
$ yarn add sequelize
# And one of the following:
$ yarn add pg pg-hstore
$ yarn add mysql2
$ yarn add sqlite3
$ yarn add tedious // MSSQL
</code></pre>
<h2 id="初期化"><a href="#%E5%88%9D%E6%9C%9F%E5%8C%96">初期化</a></h2>
<p>引き続き上記のマニュアルを見て初期化…ではなく、そこは飛ばして下記の通りにやっていきます。</p>
<p><a target="_blank" rel="nofollow noopener" href="http://docs.sequelizejs.com/manual/tutorial/migrations.html">Tutorial | Sequelize | The node.js ORM for PostgreSQL, MySQL, SQLite and MSSQL</a></p>
<p>どういうことかというと、最初のリンクの説明どおりに設定していかなくても、Sequelizeにはsequelize-cliというものもあり、それを使えばなんでもかんでもシェルでコマンド実行するだけで簡単にできてしまいます。</p>
<h3 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h3>
<p>とりあえずはsequelize-cliをインストールします。(npmの場合はマニュアルどおりです)</p>
<p>グローバルにインストールしておけば実行時にパスの指定が必要なくなります。</p>
<pre><code>yarn add sequelize-cli
</code></pre>
<h3 id="初期化"><a href="#%E5%88%9D%E6%9C%9F%E5%8C%96">初期化</a></h3>
<p>下記コマンドで初期化します。</p>
<pre><code>node_modules/.bin/sequelize init
</code></pre>
<p>これでなんか必要なファイルを全部作ってくれます。</p>
<p>config/config.jsonというファイルにデータベースへの接続情報設定がありますのでそちらに適宜入力していきます。とりあえず最初に試す時は直接入力してしまってOKです。</p>
<p>時間のある時にでも生成されたmodels/index.jsを見ればわかりますが、config.jsonにuse_env_variableの設定を入れたりすると環境変数から読み込んだりもできるので、コミットしたり本番環境を作ったりする場合はそのあたりが使えると思います。</p>
<h2 id="モデルとマイグレーションファイルを作成する"><a href="#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A8%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B">モデルとマイグレーションファイルを作成する</a></h2>
<p>ORMのため、マイグレーションファイルを作ってデータベースにテーブルを登録できるようにし、モデルを作ってアプリケーション上でデータを操作できるようにします。</p>
<p>これもコマンドで簡単に作成できます。下記は本家に書かれている例です。</p>
<pre><code class="sh">node_modules/.bin/sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string
</code></pre>
<p>これでマイグレーションファイルとモデルのファイルが作成されます。createdAt, updatedAtというタイムスタンプのカラムも自動的に追加されます。このあたりは<code>--underscored</code>オプションを付けると<code>created_at</code>, <code>updated_at</code>のようにスネークケースで作成できます。他のフレームワーク等との互換性を考えるのであれば指定しましょう。</p>
<h3 id="マイグレーションを実行"><a href="#%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E5%AE%9F%E8%A1%8C">マイグレーションを実行</a></h3>
<pre><code class="sh">node_modules/.bin/sequelize db:migrate
</code></pre>
<p>これで接続情報などが間違っていなければテーブルが作成されているはずです。</p>
<p>ちなみに僕はDBまわりだけdocker-composeを使って用意しています。(もちろんローカル等でデータベースが動いている場合には不要です)</p>
<pre><code class="yaml">version: '2'
volumes:
mysql_data:
driver: local
services:
mysql:
image: mysql:8.0
volumes:
- mysql_data:/var/lib/mysql
ports:
- 3308:3306
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
phpmyadmin:
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
- PMA_HOST=mysql
- PMA_USER=root
- PMA_PASSWORD=
ports:
- 8102:80
</code></pre>
<p>よく分からない人はmysqlのバージョンを8ではなく5.6とか5.7にしてください。そうすれば<code>http://localhost:8102</code>でphpmyadminも使えるので簡単にデータベースが作成できます。動いてすっきりしたあとにでもまた調べてバージョンを上げてみてください。(ヒント:mysql_native_password)</p>
<p>この場合接続設定はこんな感じです。</p>
<pre><code class="json"> "development": {
"username": "root",
"password": null,
"database": "yourdatabse",
"host": "127.0.0.1",
"port": "3308",
"dialect": "mysql"
},
</code></pre>
<h2 id="実際にデータを読み書き"><a href="#%E5%AE%9F%E9%9A%9B%E3%81%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E8%AA%AD%E3%81%BF%E6%9B%B8%E3%81%8D">実際にデータを読み書き</a></h2>
<p>まずはSequelizeの設定を読み込んで使えるようにします。モデルなどは自動的に読み込んでくれるのでこの1文だけでOKです。</p>
<pre><code>const models = require("../models");
</code></pre>
<p><code>../models</code>は生成されたmodelsフォルダの位置です。階層が違う場合は適宜書き換えてください。</p>
<p>ちなみにルーティングを別ファイルに分けている場合など、単にrequireしてもモデルがundefinedになっていることがありますので、その場合は最初にアプリケーションにmodelsを登録しておき、アクション内ではリクエストパラメータで取得すると良いです。</p>
<pre><code class="javascript">app.set("models", require("../models"));
</code></pre>
<pre><code class="javascript">router.post("/posts", async function(req, res, next) {
const Post = req.app.get("models").Post;
</code></pre>
<h3 id="書き込み"><a href="#%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF">書き込み</a></h3>
<p>書き込み方法はいくつかあるので一例です。</p>
<pre><code>models.User.build({
first_name: "Hoge",
last_name: "Fuga"
})
.save()
</code></pre>
<h3 id="読み込み"><a href="#%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF">読み込み</a></h3>
<p>こちらも1例です。<code>plain: true</code>で取得すると単なるオブジェクトとして利用できるようになります。</p>
<pre><code>router.get("/users", async function(req, res, next) {
const users = await models.User.findAll();
res.json(
users.map(user => {
return user.get({ plain: true });
})
);
});
</code></pre>
<p>例えばVueコンポーネント側で取得し</p>
<pre><code class="javascript"> async asyncData() {
let { users } = await axios.get("/api/users");
return { users };
}
</code></pre>
<p>受け取ったら下記のような感じで表示できます。上記の様にasyncDataで取っている場合はサーバーサイドレンダリングされています。</p>
<pre><code class="html"> <div v-for="user in users" :key="user.id">
<span>{</span><span>{</span> user.name <span>}</span><span>}</span>
</div>
</code></pre>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>とりあえずsequelize-cliがあることでかなり初期設定を短縮できています。これがなかったら特にはじめての人とかは結構つまづく箇所が多いのではないかと思います。</p>
<p>他の言語の他のフレームワークと比べてもさほど使い勝手も変わらず良さそうな感じがしました。</p>
<p>追記)TypeScriptで使うTypeORMも触ってみましたので書いておきます。<br />
<a href="https://crieit.net/posts/TypeORM-5ca0b3d5385b1">TypeORMを使ってアプリケーションを作ってみての雑感</a></p>
だら@Crieit開発者