1353 lines
67 KiB
HTML
1353 lines
67 KiB
HTML
|
|
<!DOCTYPE HTML>
|
|
<html lang="" >
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|
<title>CRUD: Reading and Writing Data · GORM Guide</title>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
<meta name="description" content="">
|
|
<meta name="generator" content="GitBook 3.2.2">
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="gitbook/style.css">
|
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-highlight/website.css">
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-search/search.css">
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<meta name="HandheldFriendly" content="true"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
|
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
|
|
<link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">
|
|
|
|
|
|
<link rel="next" href="crud.html" />
|
|
|
|
|
|
<link rel="prev" href="associations.html" />
|
|
|
|
|
|
</head>
|
|
<body>
|
|
|
|
<div class="book">
|
|
<div class="book-summary">
|
|
|
|
|
|
<div id="book-search-input" role="search">
|
|
<input type="text" placeholder="Type to search" />
|
|
</div>
|
|
|
|
|
|
<nav role="navigation">
|
|
|
|
|
|
|
|
<div class="book-summary">
|
|
|
|
<nav role="navigation">
|
|
<ul class="summary">
|
|
|
|
|
|
|
|
<li class="chapter " data-level="1.1" data-path="./">
|
|
|
|
<a href="./">
|
|
|
|
|
|
<b>1.1.</b>
|
|
|
|
Getting Started with GORM
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.2" data-path="database.html">
|
|
|
|
<a href="database.html">
|
|
|
|
|
|
<b>1.2.</b>
|
|
|
|
Database
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.2.1" data-path="database.html">
|
|
|
|
<a href="database.html#connecting-to-a-database">
|
|
|
|
|
|
<b>1.2.1.</b>
|
|
|
|
Database Connection
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.2.2" data-path="database.html">
|
|
|
|
<a href="database.html#migration">
|
|
|
|
|
|
<b>1.2.2.</b>
|
|
|
|
Migration
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3" data-path="models.html">
|
|
|
|
<a href="models.html">
|
|
|
|
|
|
<b>1.3.</b>
|
|
|
|
Models
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.3.1" data-path="models.html">
|
|
|
|
<a href="models.html#model-definition">
|
|
|
|
|
|
<b>1.3.1.</b>
|
|
|
|
Model Definition
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3.2" data-path="models.html">
|
|
|
|
<a href="models.html#conventions">
|
|
|
|
|
|
<b>1.3.2.</b>
|
|
|
|
Conventions & Overriding
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3.3" data-path="associations.html">
|
|
|
|
<a href="associations.html">
|
|
|
|
|
|
<b>1.3.3.</b>
|
|
|
|
Associations
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.3.3.1" data-path="associations.html">
|
|
|
|
<a href="associations.html#belongs-to">
|
|
|
|
|
|
<b>1.3.3.1.</b>
|
|
|
|
Belongs To
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3.3.2" data-path="associations.html">
|
|
|
|
<a href="associations.html#has-one">
|
|
|
|
|
|
<b>1.3.3.2.</b>
|
|
|
|
Has One
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3.3.3" data-path="associations.html">
|
|
|
|
<a href="associations.html#has-many">
|
|
|
|
|
|
<b>1.3.3.3.</b>
|
|
|
|
Has Many
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3.3.4" data-path="associations.html">
|
|
|
|
<a href="associations.html#many-to-many">
|
|
|
|
|
|
<b>1.3.3.4.</b>
|
|
|
|
Many To Many
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3.3.5" data-path="associations.html">
|
|
|
|
<a href="associations.html#polymorphism">
|
|
|
|
|
|
<b>1.3.3.5.</b>
|
|
|
|
Polymorphism
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.3.3.6" data-path="associations.html">
|
|
|
|
<a href="associations.html#association-mode">
|
|
|
|
|
|
<b>1.3.3.6.</b>
|
|
|
|
Association Mode
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter active" data-level="1.4" data-path="crud.html">
|
|
|
|
<a href="crud.html">
|
|
|
|
|
|
<b>1.4.</b>
|
|
|
|
CRUD: Reading and Writing Data
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.4.1" data-path="crud.html">
|
|
|
|
<a href="crud.html#create">
|
|
|
|
|
|
<b>1.4.1.</b>
|
|
|
|
Create
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4.2" data-path="crud.html">
|
|
|
|
<a href="crud.html#query">
|
|
|
|
|
|
<b>1.4.2.</b>
|
|
|
|
Query
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4.3" data-path="crud.html">
|
|
|
|
<a href="crud.html#preloading-eager-loading">
|
|
|
|
|
|
<b>1.4.3.</b>
|
|
|
|
Preloading (Eager Loading)
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4.4" data-path="crud.html">
|
|
|
|
<a href="crud.html#update">
|
|
|
|
|
|
<b>1.4.4.</b>
|
|
|
|
Update
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4.5" data-path="crud.html">
|
|
|
|
<a href="crud.html#delete">
|
|
|
|
|
|
<b>1.4.5.</b>
|
|
|
|
Delete / Soft Delete
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.4.6" data-path="crud.html">
|
|
|
|
<a href="crud.html#associations">
|
|
|
|
|
|
<b>1.4.6.</b>
|
|
|
|
Associations
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.5" data-path="callbacks.html">
|
|
|
|
<a href="callbacks.html">
|
|
|
|
|
|
<b>1.5.</b>
|
|
|
|
Callbacks
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6" data-path="advanced.html">
|
|
|
|
<a href="advanced.html">
|
|
|
|
|
|
<b>1.6.</b>
|
|
|
|
Advanced Usage
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.6.1" data-path="advanced.html">
|
|
|
|
<a href="advanced.html#error-handling">
|
|
|
|
|
|
<b>1.6.1.</b>
|
|
|
|
Error Handling
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.2" data-path="advanced.html">
|
|
|
|
<a href="advanced.html#transactions">
|
|
|
|
|
|
<b>1.6.2.</b>
|
|
|
|
Transactions
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.3" data-path="advanced.html">
|
|
|
|
<a href="advanced.html#sql-builder">
|
|
|
|
|
|
<b>1.6.3.</b>
|
|
|
|
Raw SQL & SQL Builder
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.4" data-path="advanced.html">
|
|
|
|
<a href="advanced.html#generic-database-interface-sqldb">
|
|
|
|
|
|
<b>1.6.4.</b>
|
|
|
|
Generic database interface sql.DB
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.5" data-path="advanced.html">
|
|
|
|
<a href="advanced.html#compose-primary-key">
|
|
|
|
|
|
<b>1.6.5.</b>
|
|
|
|
Composite Primary Key
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.6.6" data-path="advanced.html">
|
|
|
|
<a href="advanced.html#logger">
|
|
|
|
|
|
<b>1.6.6.</b>
|
|
|
|
Overriding Logger
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7" data-path="development.html">
|
|
|
|
<a href="development.html">
|
|
|
|
|
|
<b>1.7.</b>
|
|
|
|
Development
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<ul class="articles">
|
|
|
|
|
|
<li class="chapter " data-level="1.7.1" data-path="development.html">
|
|
|
|
<a href="development.html#architecture">
|
|
|
|
|
|
<b>1.7.1.</b>
|
|
|
|
Architecture
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.7.2" data-path="development.html">
|
|
|
|
<a href="development.html#write-plugins">
|
|
|
|
|
|
<b>1.7.2.</b>
|
|
|
|
Write Plugins
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
</li>
|
|
|
|
<li class="chapter " data-level="1.8" data-path="changelog.html">
|
|
|
|
<a href="changelog.html">
|
|
|
|
|
|
<b>1.8.</b>
|
|
|
|
Change Log
|
|
|
|
</a>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="divider"></li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
</div>
|
|
|
|
<div class="book-body">
|
|
|
|
<div class="body-inner">
|
|
|
|
|
|
|
|
<div class="book-header" role="navigation">
|
|
|
|
|
|
<!-- Title -->
|
|
<h1>
|
|
<i class="fa fa-circle-o-notch fa-spin"></i>
|
|
<a href="." >CRUD: Reading and Writing Data</a>
|
|
</h1>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="page-wrapper" tabindex="-1" role="main">
|
|
<div class="page-inner">
|
|
|
|
<div id="book-search-results">
|
|
<div class="search-noresults">
|
|
|
|
<section class="normal markdown-section">
|
|
|
|
<h1 id="crud-reading-and-writing-data">CRUD: Reading and Writing Data</h1>
|
|
<!-- toc -->
|
|
<h2 id="create">Create</h2>
|
|
<h3 id="create-record">Create Record</h3>
|
|
<pre><code class="lang-go">user := User{Name: <span class="hljs-string">"Jinzhu"</span>, Age: <span class="hljs-number">18</span>, Birthday: time.Now()}
|
|
|
|
db.NewRecord(user) <span class="hljs-comment">// => returns `true` as primary key is blank</span>
|
|
|
|
db.Create(&user)
|
|
|
|
db.NewRecord(user) <span class="hljs-comment">// => return `false` after `user` created</span>
|
|
</code></pre>
|
|
<h3 id="default-values">Default Values</h3>
|
|
<p>You could define default value in the <code>gorm</code> tag, then the inserting SQL will ignore these fields that has default value and its value is blank, and after insert the record into database, gorm will load those fields's value from database.</p>
|
|
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Animal <span class="hljs-keyword">struct</span> {
|
|
ID <span class="hljs-keyword">int64</span>
|
|
Name <span class="hljs-keyword">string</span> <span class="hljs-string">`gorm:"default:'galeone'"`</span>
|
|
Age <span class="hljs-keyword">int64</span>
|
|
}
|
|
|
|
<span class="hljs-keyword">var</span> animal = Animal{Age: <span class="hljs-number">99</span>, Name: <span class="hljs-string">""</span>}
|
|
db.Create(&animal)
|
|
<span class="hljs-comment">// INSERT INTO animals("age") values('99');</span>
|
|
<span class="hljs-comment">// SELECT name from animals WHERE ID=111; // the returning primary key is 111</span>
|
|
<span class="hljs-comment">// animal.Name => 'galeone'</span>
|
|
</code></pre>
|
|
<h3 id="setting-primary-key-in-callbacks">Setting Primary Key In Callbacks</h3>
|
|
<p>If you want to set primary field's value in <code>BeforeCreate</code> callback, you could use <code>scope.SetColumn</code>, for example:</p>
|
|
<pre><code class="lang-go"><span class="hljs-keyword">func</span> (user *User) BeforeCreate(scope *gorm.Scope) error {
|
|
scope.SetColumn(<span class="hljs-string">"ID"</span>, uuid.New())
|
|
<span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
|
|
}
|
|
</code></pre>
|
|
<h3 id="extra-creating-option">Extra Creating option</h3>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Add extra SQL option for inserting SQL</span>
|
|
db.Set(<span class="hljs-string">"gorm:insert_option"</span>, <span class="hljs-string">"ON CONFLICT"</span>).Create(&product)
|
|
<span class="hljs-comment">// INSERT INTO products (name, code) VALUES ("name", "code") ON CONFLICT;</span>
|
|
</code></pre>
|
|
<h2 id="query">Query</h2>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Get first record, order by primary key</span>
|
|
db.First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users ORDER BY id LIMIT 1;</span>
|
|
|
|
<span class="hljs-comment">// Get last record, order by primary key</span>
|
|
db.Last(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users ORDER BY id DESC LIMIT 1;</span>
|
|
|
|
<span class="hljs-comment">// Get all records</span>
|
|
db.Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users;</span>
|
|
|
|
<span class="hljs-comment">// Get record with primary key (only works for integer primary key)</span>
|
|
db.First(&user, <span class="hljs-number">10</span>)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE id = 10;</span>
|
|
</code></pre>
|
|
<h3 id="query-with-where-plain-sql">Query With Where (Plain SQL)</h3>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Get first matched record</span>
|
|
db.Where(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>).First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;</span>
|
|
|
|
<span class="hljs-comment">// Get all matched records</span>
|
|
db.Where(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = 'jinzhu';</span>
|
|
|
|
db.Where(<span class="hljs-string">"name <> ?"</span>, <span class="hljs-string">"jinzhu"</span>).Find(&users)
|
|
|
|
<span class="hljs-comment">// IN</span>
|
|
db.Where(<span class="hljs-string">"name in (?)"</span>, []<span class="hljs-keyword">string</span>{<span class="hljs-string">"jinzhu"</span>, <span class="hljs-string">"jinzhu 2"</span>}).Find(&users)
|
|
|
|
<span class="hljs-comment">// LIKE</span>
|
|
db.Where(<span class="hljs-string">"name LIKE ?"</span>, <span class="hljs-string">"%jin%"</span>).Find(&users)
|
|
|
|
<span class="hljs-comment">// AND</span>
|
|
db.Where(<span class="hljs-string">"name = ? AND age >= ?"</span>, <span class="hljs-string">"jinzhu"</span>, <span class="hljs-string">"22"</span>).Find(&users)
|
|
|
|
<span class="hljs-comment">// Time</span>
|
|
db.Where(<span class="hljs-string">"updated_at > ?"</span>, lastWeek).Find(&users)
|
|
|
|
db.Where(<span class="hljs-string">"created_at BETWEEN ? AND ?"</span>, lastWeek, today).Find(&users)
|
|
</code></pre>
|
|
<h3 id="query-with-where-struct--map">Query With Where (Struct & Map)</h3>
|
|
<p><strong>NOTE</strong> When query with struct, GORM will only query with those fields has value</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Struct</span>
|
|
db.Where(&User{Name: <span class="hljs-string">"jinzhu"</span>, Age: <span class="hljs-number">20</span>}).First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;</span>
|
|
|
|
<span class="hljs-comment">// Map</span>
|
|
db.Where(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"name"</span>: <span class="hljs-string">"jinzhu"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">20</span>}).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;</span>
|
|
|
|
<span class="hljs-comment">// Slice of primary keys</span>
|
|
db.Where([]<span class="hljs-keyword">int64</span>{<span class="hljs-number">20</span>, <span class="hljs-number">21</span>, <span class="hljs-number">22</span>}).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE id IN (20, 21, 22);</span>
|
|
</code></pre>
|
|
<h3 id="query-with-not">Query With Not</h3>
|
|
<pre><code class="lang-go">db.Not(<span class="hljs-string">"name"</span>, <span class="hljs-string">"jinzhu"</span>).First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;</span>
|
|
|
|
<span class="hljs-comment">// Not In</span>
|
|
db.Not(<span class="hljs-string">"name"</span>, []<span class="hljs-keyword">string</span>{<span class="hljs-string">"jinzhu"</span>, <span class="hljs-string">"jinzhu 2"</span>}).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");</span>
|
|
|
|
<span class="hljs-comment">// Not In slice of primary keys</span>
|
|
db.Not([]<span class="hljs-keyword">int64</span>{<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>}).First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE id NOT IN (1,2,3);</span>
|
|
|
|
db.Not([]<span class="hljs-keyword">int64</span>{}).First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users;</span>
|
|
|
|
<span class="hljs-comment">// Plain SQL</span>
|
|
db.Not(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>).First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE NOT(name = "jinzhu");</span>
|
|
|
|
<span class="hljs-comment">// Struct</span>
|
|
db.Not(User{Name: <span class="hljs-string">"jinzhu"</span>}).First(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name <> "jinzhu";</span>
|
|
</code></pre>
|
|
<h3 id="query-with-inline-condition">Query With Inline Condition</h3>
|
|
<p><strong>NOTE</strong> When query with primary key, you should carefully check the value you passed is a valid primary key, to avoid SQL injection</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Get by primary key (only works for integer primary key)</span>
|
|
db.First(&user, <span class="hljs-number">23</span>)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE id = 23 LIMIT 1;</span>
|
|
<span class="hljs-comment">// Get by primary key if it were a non-integer type</span>
|
|
db.First(&user, <span class="hljs-string">"id = ?"</span>, <span class="hljs-string">"string_primary_key"</span>)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE id = 'string_primary_key' LIMIT 1;</span>
|
|
|
|
<span class="hljs-comment">// Plain SQL</span>
|
|
db.Find(&user, <span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = "jinzhu";</span>
|
|
|
|
db.Find(&users, <span class="hljs-string">"name <> ? AND age > ?"</span>, <span class="hljs-string">"jinzhu"</span>, <span class="hljs-number">20</span>)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;</span>
|
|
|
|
<span class="hljs-comment">// Struct</span>
|
|
db.Find(&users, User{Age: <span class="hljs-number">20</span>})
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE age = 20;</span>
|
|
|
|
<span class="hljs-comment">// Map</span>
|
|
db.Find(&users, <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"age"</span>: <span class="hljs-number">20</span>})
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE age = 20;</span>
|
|
</code></pre>
|
|
<h3 id="query-with-or">Query With Or</h3>
|
|
<pre><code class="lang-go">db.Where(<span class="hljs-string">"role = ?"</span>, <span class="hljs-string">"admin"</span>).Or(<span class="hljs-string">"role = ?"</span>, <span class="hljs-string">"super_admin"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';</span>
|
|
|
|
<span class="hljs-comment">// Struct</span>
|
|
db.Where(<span class="hljs-string">"name = 'jinzhu'"</span>).Or(User{Name: <span class="hljs-string">"jinzhu 2"</span>}).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';</span>
|
|
|
|
<span class="hljs-comment">// Map</span>
|
|
db.Where(<span class="hljs-string">"name = 'jinzhu'"</span>).Or(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"name"</span>: <span class="hljs-string">"jinzhu 2"</span>}).Find(&users)
|
|
</code></pre>
|
|
<h3 id="query-chains">Query Chains</h3>
|
|
<p>Gorm has a chainable API, you could use it like this</p>
|
|
<pre><code class="lang-go">db.Where(<span class="hljs-string">"name <> ?"</span>,<span class="hljs-string">"jinzhu"</span>).Where(<span class="hljs-string">"age >= ? and role <> ?"</span>,<span class="hljs-number">20</span>,<span class="hljs-string">"admin"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name <> 'jinzhu' AND age >= 20 AND role <> 'admin';</span>
|
|
|
|
db.Where(<span class="hljs-string">"role = ?"</span>, <span class="hljs-string">"admin"</span>).Or(<span class="hljs-string">"role = ?"</span>, <span class="hljs-string">"super_admin"</span>).Not(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>).Find(&users)
|
|
</code></pre>
|
|
<h3 id="extra-querying-option">Extra Querying option</h3>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Add extra SQL option for selecting SQL</span>
|
|
db.Set(<span class="hljs-string">"gorm:query_option"</span>, <span class="hljs-string">"FOR UPDATE"</span>).First(&user, <span class="hljs-number">10</span>)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE id = 10 FOR UPDATE;</span>
|
|
</code></pre>
|
|
<h3 id="firstorinit">FirstOrInit</h3>
|
|
<p>Get first matched record, or initalize a new one with given conditions (only works with struct, map conditions)</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Unfound</span>
|
|
db.FirstOrInit(&user, User{Name: <span class="hljs-string">"non_existing"</span>})
|
|
<span class="hljs-comment">//// user -> User{Name: "non_existing"}</span>
|
|
|
|
<span class="hljs-comment">// Found</span>
|
|
db.Where(User{Name: <span class="hljs-string">"Jinzhu"</span>}).FirstOrInit(&user)
|
|
<span class="hljs-comment">//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}</span>
|
|
db.FirstOrInit(&user, <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"name"</span>: <span class="hljs-string">"jinzhu"</span>})
|
|
<span class="hljs-comment">//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}</span>
|
|
</code></pre>
|
|
<h4 id="attrs">Attrs</h4>
|
|
<p>Initalize struct with argument if record haven't been found</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Unfound</span>
|
|
db.Where(User{Name: <span class="hljs-string">"non_existing"</span>}).Attrs(User{Age: <span class="hljs-number">20</span>}).FirstOrInit(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM USERS WHERE name = 'non_existing';</span>
|
|
<span class="hljs-comment">//// user -> User{Name: "non_existing", Age: 20}</span>
|
|
|
|
db.Where(User{Name: <span class="hljs-string">"non_existing"</span>}).Attrs(<span class="hljs-string">"age"</span>, <span class="hljs-number">20</span>).FirstOrInit(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM USERS WHERE name = 'non_existing';</span>
|
|
<span class="hljs-comment">//// user -> User{Name: "non_existing", Age: 20}</span>
|
|
|
|
<span class="hljs-comment">// Found</span>
|
|
db.Where(User{Name: <span class="hljs-string">"Jinzhu"</span>}).Attrs(User{Age: <span class="hljs-number">30</span>}).FirstOrInit(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM USERS WHERE name = jinzhu';</span>
|
|
<span class="hljs-comment">//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}</span>
|
|
</code></pre>
|
|
<h4 id="assign">Assign</h4>
|
|
<p>Assign argument to results regardless it is found or not</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Unfound</span>
|
|
db.Where(User{Name: <span class="hljs-string">"non_existing"</span>}).Assign(User{Age: <span class="hljs-number">20</span>}).FirstOrInit(&user)
|
|
<span class="hljs-comment">//// user -> User{Name: "non_existing", Age: 20}</span>
|
|
|
|
<span class="hljs-comment">// Found</span>
|
|
db.Where(User{Name: <span class="hljs-string">"Jinzhu"</span>}).Assign(User{Age: <span class="hljs-number">30</span>}).FirstOrInit(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM USERS WHERE name = jinzhu';</span>
|
|
<span class="hljs-comment">//// user -> User{Id: 111, Name: "Jinzhu", Age: 30}</span>
|
|
</code></pre>
|
|
<h3 id="firstorcreate">FirstOrCreate</h3>
|
|
<p>Get first matched record, or create a new one with given conditions (only works with struct, map conditions)</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Unfound</span>
|
|
db.FirstOrCreate(&user, User{Name: <span class="hljs-string">"non_existing"</span>})
|
|
<span class="hljs-comment">//// INSERT INTO "users" (name) VALUES ("non_existing");</span>
|
|
<span class="hljs-comment">//// user -> User{Id: 112, Name: "non_existing"}</span>
|
|
|
|
<span class="hljs-comment">// Found</span>
|
|
db.Where(User{Name: <span class="hljs-string">"Jinzhu"</span>}).FirstOrCreate(&user)
|
|
<span class="hljs-comment">//// user -> User{Id: 111, Name: "Jinzhu"}</span>
|
|
</code></pre>
|
|
<h4 id="attrs">Attrs</h4>
|
|
<p>Assgin struct with argument if record haven't been found</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Unfound</span>
|
|
db.Where(User{Name: <span class="hljs-string">"non_existing"</span>}).Attrs(User{Age: <span class="hljs-number">20</span>}).FirstOrCreate(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = 'non_existing';</span>
|
|
<span class="hljs-comment">//// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);</span>
|
|
<span class="hljs-comment">//// user -> User{Id: 112, Name: "non_existing", Age: 20}</span>
|
|
|
|
<span class="hljs-comment">// Found</span>
|
|
db.Where(User{Name: <span class="hljs-string">"jinzhu"</span>}).Attrs(User{Age: <span class="hljs-number">30</span>}).FirstOrCreate(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = 'jinzhu';</span>
|
|
<span class="hljs-comment">//// user -> User{Id: 111, Name: "jinzhu", Age: 20}</span>
|
|
</code></pre>
|
|
<h4 id="assign">Assign</h4>
|
|
<p>Assign it to the record regardless it is found or not, and save back to database.</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Unfound</span>
|
|
db.Where(User{Name: <span class="hljs-string">"non_existing"</span>}).Assign(User{Age: <span class="hljs-number">20</span>}).FirstOrCreate(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = 'non_existing';</span>
|
|
<span class="hljs-comment">//// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);</span>
|
|
<span class="hljs-comment">//// user -> User{Id: 112, Name: "non_existing", Age: 20}</span>
|
|
|
|
<span class="hljs-comment">// Found</span>
|
|
db.Where(User{Name: <span class="hljs-string">"jinzhu"</span>}).Assign(User{Age: <span class="hljs-number">30</span>}).FirstOrCreate(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE name = 'jinzhu';</span>
|
|
<span class="hljs-comment">//// UPDATE users SET age=30 WHERE id = 111;</span>
|
|
<span class="hljs-comment">//// user -> User{Id: 111, Name: "jinzhu", Age: 30}</span>
|
|
</code></pre>
|
|
<h3 id="select">Select</h3>
|
|
<p>Specify fields that you want to retrieve from database, by default, will select all fields;</p>
|
|
<pre><code class="lang-go">db.Select(<span class="hljs-string">"name, age"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT name, age FROM users;</span>
|
|
|
|
db.Select([]<span class="hljs-keyword">string</span>{<span class="hljs-string">"name"</span>, <span class="hljs-string">"age"</span>}).Find(&users)
|
|
<span class="hljs-comment">//// SELECT name, age FROM users;</span>
|
|
|
|
db.Table(<span class="hljs-string">"users"</span>).Select(<span class="hljs-string">"COALESCE(age,?)"</span>, <span class="hljs-number">42</span>).Rows()
|
|
<span class="hljs-comment">//// SELECT COALESCE(age,'42') FROM users;</span>
|
|
</code></pre>
|
|
<h3 id="order">Order</h3>
|
|
<p>Specify order when retrieve records from database, set reorder to <code>true</code> to overwrite defined conditions</p>
|
|
<pre><code class="lang-go">db.Order(<span class="hljs-string">"age desc, name"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users ORDER BY age desc, name;</span>
|
|
|
|
<span class="hljs-comment">// Multiple orders</span>
|
|
db.Order(<span class="hljs-string">"age desc"</span>).Order(<span class="hljs-string">"name"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users ORDER BY age desc, name;</span>
|
|
|
|
<span class="hljs-comment">// ReOrder</span>
|
|
db.Order(<span class="hljs-string">"age desc"</span>).Find(&users1).Order(<span class="hljs-string">"age"</span>, <span class="hljs-literal">true</span>).Find(&users2)
|
|
<span class="hljs-comment">//// SELECT * FROM users ORDER BY age desc; (users1)</span>
|
|
<span class="hljs-comment">//// SELECT * FROM users ORDER BY age; (users2)</span>
|
|
</code></pre>
|
|
<h3 id="limit">Limit</h3>
|
|
<p>Specify the number of records to be retrieved</p>
|
|
<pre><code class="lang-go">db.Limit(<span class="hljs-number">3</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users LIMIT 3;</span>
|
|
|
|
<span class="hljs-comment">// Cancel limit condition with -1</span>
|
|
db.Limit(<span class="hljs-number">10</span>).Find(&users1).Limit(<span class="hljs-number">-1</span>).Find(&users2)
|
|
<span class="hljs-comment">//// SELECT * FROM users LIMIT 10; (users1)</span>
|
|
<span class="hljs-comment">//// SELECT * FROM users; (users2)</span>
|
|
</code></pre>
|
|
<h3 id="offset">Offset</h3>
|
|
<p>Specify the number of records to skip before starting to return the records</p>
|
|
<pre><code class="lang-go">db.Offset(<span class="hljs-number">3</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users OFFSET 3;</span>
|
|
|
|
<span class="hljs-comment">// Cancel offset condition with -1</span>
|
|
db.Offset(<span class="hljs-number">10</span>).Find(&users1).Offset(<span class="hljs-number">-1</span>).Find(&users2)
|
|
<span class="hljs-comment">//// SELECT * FROM users OFFSET 10; (users1)</span>
|
|
<span class="hljs-comment">//// SELECT * FROM users; (users2)</span>
|
|
</code></pre>
|
|
<h3 id="count">Count</h3>
|
|
<p>Get how many records for a model</p>
|
|
<pre><code class="lang-go">db.Where(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>).Or(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu 2"</span>).Find(&users).Count(&count)
|
|
<span class="hljs-comment">//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)</span>
|
|
<span class="hljs-comment">//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)</span>
|
|
|
|
db.Model(&User{}).Where(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>).Count(&count)
|
|
<span class="hljs-comment">//// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)</span>
|
|
|
|
db.Table(<span class="hljs-string">"deleted_users"</span>).Count(&count)
|
|
<span class="hljs-comment">//// SELECT count(*) FROM deleted_users;</span>
|
|
</code></pre>
|
|
<h3 id="group--having">Group & Having</h3>
|
|
<pre><code class="lang-go">rows, err := db.Table(<span class="hljs-string">"orders"</span>).Select(<span class="hljs-string">"date(created_at) as date, sum(amount) as total"</span>).Group(<span class="hljs-string">"date(created_at)"</span>).Rows()
|
|
<span class="hljs-keyword">for</span> rows.Next() {
|
|
...
|
|
}
|
|
|
|
rows, err := db.Table(<span class="hljs-string">"orders"</span>).Select(<span class="hljs-string">"date(created_at) as date, sum(amount) as total"</span>).Group(<span class="hljs-string">"date(created_at)"</span>).Having(<span class="hljs-string">"sum(amount) > ?"</span>, <span class="hljs-number">100</span>).Rows()
|
|
<span class="hljs-keyword">for</span> rows.Next() {
|
|
...
|
|
}
|
|
|
|
<span class="hljs-keyword">type</span> Result <span class="hljs-keyword">struct</span> {
|
|
Date time.Time
|
|
Total <span class="hljs-keyword">int64</span>
|
|
}
|
|
db.Table(<span class="hljs-string">"orders"</span>).Select(<span class="hljs-string">"date(created_at) as date, sum(amount) as total"</span>).Group(<span class="hljs-string">"date(created_at)"</span>).Having(<span class="hljs-string">"sum(amount) > ?"</span>, <span class="hljs-number">100</span>).Scan(&results)
|
|
</code></pre>
|
|
<h3 id="joins">Joins</h3>
|
|
<p>Specify Joins conditions</p>
|
|
<pre><code class="lang-go">rows, err := db.Table(<span class="hljs-string">"users"</span>).Select(<span class="hljs-string">"users.name, emails.email"</span>).Joins(<span class="hljs-string">"left join emails on emails.user_id = users.id"</span>).Rows()
|
|
<span class="hljs-keyword">for</span> rows.Next() {
|
|
...
|
|
}
|
|
|
|
db.Table(<span class="hljs-string">"users"</span>).Select(<span class="hljs-string">"users.name, emails.email"</span>).Joins(<span class="hljs-string">"left join emails on emails.user_id = users.id"</span>).Scan(&results)
|
|
|
|
<span class="hljs-comment">// multiple joins with parameter</span>
|
|
db.Joins(<span class="hljs-string">"JOIN emails ON emails.user_id = users.id AND emails.email = ?"</span>, <span class="hljs-string">"jinzhu@example.org"</span>).Joins(<span class="hljs-string">"JOIN credit_cards ON credit_cards.user_id = users.id"</span>).Where(<span class="hljs-string">"credit_cards.number = ?"</span>, <span class="hljs-string">"411111111111"</span>).Find(&user)
|
|
</code></pre>
|
|
<h3 id="pluck">Pluck</h3>
|
|
<p>Query single column from a model as a map, if you want to query multiple columns, you could use <a href="#scan"><code>Scan</code></a></p>
|
|
<pre><code class="lang-go"><span class="hljs-keyword">var</span> ages []<span class="hljs-keyword">int64</span>
|
|
db.Find(&users).Pluck(<span class="hljs-string">"age"</span>, &ages)
|
|
|
|
<span class="hljs-keyword">var</span> names []<span class="hljs-keyword">string</span>
|
|
db.Model(&User{}).Pluck(<span class="hljs-string">"name"</span>, &names)
|
|
|
|
db.Table(<span class="hljs-string">"deleted_users"</span>).Pluck(<span class="hljs-string">"name"</span>, &names)
|
|
|
|
<span class="hljs-comment">// Requesting more than one column? Do it like this:</span>
|
|
db.Select(<span class="hljs-string">"name, age"</span>).Find(&users)
|
|
</code></pre>
|
|
<h3 id="scan">Scan</h3>
|
|
<p>Scan results into another struct.</p>
|
|
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Result <span class="hljs-keyword">struct</span> {
|
|
Name <span class="hljs-keyword">string</span>
|
|
Age <span class="hljs-keyword">int</span>
|
|
}
|
|
|
|
<span class="hljs-keyword">var</span> result Result
|
|
db.Table(<span class="hljs-string">"users"</span>).Select(<span class="hljs-string">"name, age"</span>).Where(<span class="hljs-string">"name = ?"</span>, <span class="hljs-number">3</span>).Scan(&result)
|
|
|
|
<span class="hljs-comment">// Raw SQL</span>
|
|
db.Raw(<span class="hljs-string">"SELECT name, age FROM users WHERE name = ?"</span>, <span class="hljs-number">3</span>).Scan(&result)
|
|
</code></pre>
|
|
<h3 id="scopes">Scopes</h3>
|
|
<p>Pass current database connection to <code>func(*DB) *DB</code>, which could be used to add conditions dynamically</p>
|
|
<pre><code class="lang-go"><span class="hljs-keyword">func</span> AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
|
|
<span class="hljs-keyword">return</span> db.Where(<span class="hljs-string">"amount > ?"</span>, <span class="hljs-number">1000</span>)
|
|
}
|
|
|
|
<span class="hljs-keyword">func</span> PaidWithCreditCard(db *gorm.DB) *gorm.DB {
|
|
<span class="hljs-keyword">return</span> db.Where(<span class="hljs-string">"pay_mode_sign = ?"</span>, <span class="hljs-string">"C"</span>)
|
|
}
|
|
|
|
<span class="hljs-keyword">func</span> PaidWithCod(db *gorm.DB) *gorm.DB {
|
|
<span class="hljs-keyword">return</span> db.Where(<span class="hljs-string">"pay_mode_sign = ?"</span>, <span class="hljs-string">"C"</span>)
|
|
}
|
|
|
|
<span class="hljs-keyword">func</span> OrderStatus(status []<span class="hljs-keyword">string</span>) <span class="hljs-keyword">func</span> (db *gorm.DB) *gorm.DB {
|
|
<span class="hljs-keyword">return</span> <span class="hljs-keyword">func</span> (db *gorm.DB) *gorm.DB {
|
|
<span class="hljs-keyword">return</span> db.Scopes(AmountGreaterThan1000).Where(<span class="hljs-string">"status in (?)"</span>, status)
|
|
}
|
|
}
|
|
|
|
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
|
|
<span class="hljs-comment">// Find all credit card orders and amount greater than 1000</span>
|
|
|
|
db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
|
|
<span class="hljs-comment">// Find all COD orders and amount greater than 1000</span>
|
|
|
|
db.Scopes(OrderStatus([]<span class="hljs-keyword">string</span>{<span class="hljs-string">"paid"</span>, <span class="hljs-string">"shipped"</span>})).Find(&orders)
|
|
<span class="hljs-comment">// Find all paid, shipped orders</span>
|
|
</code></pre>
|
|
<h3 id="specifying-the-table-name">Specifying The Table Name</h3>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Create `deleted_users` table with struct User's definition</span>
|
|
db.Table(<span class="hljs-string">"deleted_users"</span>).CreateTable(&User{})
|
|
|
|
<span class="hljs-keyword">var</span> deleted_users []User
|
|
db.Table(<span class="hljs-string">"deleted_users"</span>).Find(&deleted_users)
|
|
<span class="hljs-comment">//// SELECT * FROM deleted_users;</span>
|
|
|
|
db.Table(<span class="hljs-string">"deleted_users"</span>).Where(<span class="hljs-string">"name = ?"</span>, <span class="hljs-string">"jinzhu"</span>).Delete()
|
|
<span class="hljs-comment">//// DELETE FROM deleted_users WHERE name = 'jinzhu';</span>
|
|
</code></pre>
|
|
<h2 id="preloading-eager-loading">Preloading (Eager loading)</h2>
|
|
<pre><code class="lang-go">db.Preload(<span class="hljs-string">"Orders"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users;</span>
|
|
<span class="hljs-comment">//// SELECT * FROM orders WHERE user_id IN (1,2,3,4);</span>
|
|
|
|
db.Preload(<span class="hljs-string">"Orders"</span>, <span class="hljs-string">"state NOT IN (?)"</span>, <span class="hljs-string">"cancelled"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users;</span>
|
|
<span class="hljs-comment">//// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');</span>
|
|
|
|
db.Where(<span class="hljs-string">"state = ?"</span>, <span class="hljs-string">"active"</span>).Preload(<span class="hljs-string">"Orders"</span>, <span class="hljs-string">"state NOT IN (?)"</span>, <span class="hljs-string">"cancelled"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE state = 'active';</span>
|
|
<span class="hljs-comment">//// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');</span>
|
|
|
|
db.Preload(<span class="hljs-string">"Orders"</span>).Preload(<span class="hljs-string">"Profile"</span>).Preload(<span class="hljs-string">"Role"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users;</span>
|
|
<span class="hljs-comment">//// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many</span>
|
|
<span class="hljs-comment">//// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one</span>
|
|
<span class="hljs-comment">//// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to</span>
|
|
</code></pre>
|
|
<h4 id="custom-preloading-sql">Custom Preloading SQL</h4>
|
|
<p>You could custom preloading SQL by passing in <code>func(db *gorm.DB) *gorm.DB</code> (same type as the one used for <a href="#scopes">Scopes</a>), for example:</p>
|
|
<pre><code class="lang-go">db.Preload(<span class="hljs-string">"Orders"</span>, <span class="hljs-keyword">func</span>(db *gorm.DB) *gorm.DB {
|
|
<span class="hljs-keyword">return</span> db.Order(<span class="hljs-string">"orders.amount DESC"</span>)
|
|
}).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users;</span>
|
|
<span class="hljs-comment">//// SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;</span>
|
|
</code></pre>
|
|
<h3 id="nested-preloading">Nested Preloading</h3>
|
|
<pre><code class="lang-go">db.Preload(<span class="hljs-string">"Orders.OrderItems"</span>).Find(&users)
|
|
db.Preload(<span class="hljs-string">"Orders"</span>, <span class="hljs-string">"state = ?"</span>, <span class="hljs-string">"paid"</span>).Preload(<span class="hljs-string">"Orders.OrderItems"</span>).Find(&users)
|
|
</code></pre>
|
|
<h2 id="update">Update</h2>
|
|
<h3 id="update-all-fields">Update All Fields</h3>
|
|
<p><code>Save</code> will include all fields when perform the Updating SQL, even it is not changed</p>
|
|
<pre><code class="lang-go">db.First(&user)
|
|
|
|
user.Name = <span class="hljs-string">"jinzhu 2"</span>
|
|
user.Age = <span class="hljs-number">100</span>
|
|
db.Save(&user)
|
|
|
|
<span class="hljs-comment">//// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;</span>
|
|
</code></pre>
|
|
<h3 id="update-changed-fields">Update Changed Fields</h3>
|
|
<p>If you only want to update changed Fields, you could use <code>Update</code>, <code>Updates</code></p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Update single attribute if it is changed</span>
|
|
db.Model(&user).Update(<span class="hljs-string">"name"</span>, <span class="hljs-string">"hello"</span>)
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;</span>
|
|
|
|
<span class="hljs-comment">// Update single attribute with combined conditions</span>
|
|
db.Model(&user).Where(<span class="hljs-string">"active = ?"</span>, <span class="hljs-literal">true</span>).Update(<span class="hljs-string">"name"</span>, <span class="hljs-string">"hello"</span>)
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;</span>
|
|
|
|
<span class="hljs-comment">// Update multiple attributes with `map`, will only update those changed fields</span>
|
|
db.Model(&user).Updates(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"name"</span>: <span class="hljs-string">"hello"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>, <span class="hljs-string">"actived"</span>: <span class="hljs-literal">false</span>})
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;</span>
|
|
|
|
<span class="hljs-comment">// Update multiple attributes with `struct`, will only update those changed & non blank fields</span>
|
|
db.Model(&user).Updates(User{Name: <span class="hljs-string">"hello"</span>, Age: <span class="hljs-number">18</span>})
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;</span>
|
|
|
|
<span class="hljs-comment">// WARNING when update with struct, GORM will only update those fields that with non blank value</span>
|
|
<span class="hljs-comment">// For below Update, nothing will be updated as "", 0, false are blank values of their types</span>
|
|
db.Model(&user).Updates(User{Name: <span class="hljs-string">""</span>, Age: <span class="hljs-number">0</span>, Actived: <span class="hljs-literal">false</span>})
|
|
</code></pre>
|
|
<h3 id="update-selected-fields">Update Selected Fields</h3>
|
|
<p>If you only want to update or ignore some fields when updating, you could use <code>Select</code>, <code>Omit</code></p>
|
|
<pre><code class="lang-go">db.Model(&user).Select(<span class="hljs-string">"name"</span>).Updates(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"name"</span>: <span class="hljs-string">"hello"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>, <span class="hljs-string">"actived"</span>: <span class="hljs-literal">false</span>})
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;</span>
|
|
|
|
db.Model(&user).Omit(<span class="hljs-string">"name"</span>).Updates(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"name"</span>: <span class="hljs-string">"hello"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>, <span class="hljs-string">"actived"</span>: <span class="hljs-literal">false</span>})
|
|
<span class="hljs-comment">//// UPDATE users SET age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;</span>
|
|
</code></pre>
|
|
<h3 id="update-changed-fields-without-callbacks">Update Changed Fields Without Callbacks</h3>
|
|
<p>Above updating operations will perform the model's <code>BeforeUpdate</code>, <code>AfterUpdate</code> method, update its <code>UpdatedAt</code> timestamp, save its <code>Associations</code> when updaing, if you don't want to call them, you could use <code>UpdateColumn</code>, <code>UpdateColumns</code></p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Update single attribute, similar with `Update`</span>
|
|
db.Model(&user).UpdateColumn(<span class="hljs-string">"name"</span>, <span class="hljs-string">"hello"</span>)
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello' WHERE id = 111;</span>
|
|
|
|
<span class="hljs-comment">// Update multiple attributes, similar with `Updates`</span>
|
|
db.Model(&user).UpdateColumns(User{Name: <span class="hljs-string">"hello"</span>, Age: <span class="hljs-number">18</span>})
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', age=18 WHERE id = 111;</span>
|
|
</code></pre>
|
|
<h3 id="batch-updates">Batch Updates</h3>
|
|
<p>Callbacks won't run when do batch updates</p>
|
|
<pre><code class="lang-go">db.Table(<span class="hljs-string">"users"</span>).Where(<span class="hljs-string">"id IN (?)"</span>, []<span class="hljs-keyword">int</span>{<span class="hljs-number">10</span>, <span class="hljs-number">11</span>}).Updates(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"name"</span>: <span class="hljs-string">"hello"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>})
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);</span>
|
|
|
|
<span class="hljs-comment">// Update with struct only works with none zero values, or use map[string]interface{}</span>
|
|
db.Model(User{}).Updates(User{Name: <span class="hljs-string">"hello"</span>, Age: <span class="hljs-number">18</span>})
|
|
<span class="hljs-comment">//// UPDATE users SET name='hello', age=18;</span>
|
|
|
|
<span class="hljs-comment">// Get updated records count with `RowsAffected`</span>
|
|
db.Model(User{}).Updates(User{Name: <span class="hljs-string">"hello"</span>, Age: <span class="hljs-number">18</span>}).RowsAffected
|
|
</code></pre>
|
|
<h3 id="update-with-sql-expression">Update with SQL Expression</h3>
|
|
<pre><code class="lang-go">DB.Model(&product).Update(<span class="hljs-string">"price"</span>, gorm.Expr(<span class="hljs-string">"price * ? + ?"</span>, <span class="hljs-number">2</span>, <span class="hljs-number">100</span>))
|
|
<span class="hljs-comment">//// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';</span>
|
|
|
|
DB.Model(&product).Updates(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">interface</span>{}{<span class="hljs-string">"price"</span>: gorm.Expr(<span class="hljs-string">"price * ? + ?"</span>, <span class="hljs-number">2</span>, <span class="hljs-number">100</span>)})
|
|
<span class="hljs-comment">//// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';</span>
|
|
|
|
DB.Model(&product).UpdateColumn(<span class="hljs-string">"quantity"</span>, gorm.Expr(<span class="hljs-string">"quantity - ?"</span>, <span class="hljs-number">1</span>))
|
|
<span class="hljs-comment">//// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2';</span>
|
|
|
|
DB.Model(&product).Where(<span class="hljs-string">"quantity > 1"</span>).UpdateColumn(<span class="hljs-string">"quantity"</span>, gorm.Expr(<span class="hljs-string">"quantity - ?"</span>, <span class="hljs-number">1</span>))
|
|
<span class="hljs-comment">//// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2' AND quantity > 1;</span>
|
|
</code></pre>
|
|
<h3 id="change-updating-values-in-callbacks">Change Updating Values In Callbacks</h3>
|
|
<p>If you want to change updating values in callbacks using <code>BeforeUpdate</code>, <code>BeforeSave</code>, you could use <code>scope.SetColumn</code>, for example:</p>
|
|
<pre><code class="lang-go"><span class="hljs-keyword">func</span> (user *User) BeforeSave(scope *gorm.Scope) (err error) {
|
|
<span class="hljs-keyword">if</span> pw, err := bcrypt.GenerateFromPassword(user.Password, <span class="hljs-number">0</span>); err == <span class="hljs-literal">nil</span> {
|
|
scope.SetColumn(<span class="hljs-string">"EncryptedPassword"</span>, pw)
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h3 id="extra-updating-option">Extra Updating option</h3>
|
|
<pre><code class="lang-go">// Add extra SQL option for updating SQL
|
|
db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name, "hello")
|
|
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 OPTION (OPTIMIZE FOR UNKNOWN);
|
|
</code></pre>
|
|
<h2 id="delete">Delete</h2>
|
|
<p><strong>WARNING</strong> When delete a record, you need to ensure it's primary field has value, and GORM will use the primary key to delete the record, if primary field's blank, GORM will delete all records for the model</p>
|
|
<pre><code class="lang-go"><span class="hljs-comment">// Delete an existing record</span>
|
|
db.Delete(&email)
|
|
<span class="hljs-comment">//// DELETE from emails where id=10;</span>
|
|
|
|
<span class="hljs-comment">// Add extra SQL option for deleting SQL</span>
|
|
db.Set(<span class="hljs-string">"gorm:delete_option"</span>, <span class="hljs-string">"OPTION (OPTIMIZE FOR UNKNOWN)"</span>).Delete(&email)
|
|
<span class="hljs-comment">//// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);</span>
|
|
</code></pre>
|
|
<h3 id="batch-delete">Batch Delete</h3>
|
|
<p>Delete all matched records</p>
|
|
<pre><code class="lang-go">db.Where(<span class="hljs-string">"email LIKE ?"</span>, <span class="hljs-string">"%jinzhu%"</span>).Delete(Email{})
|
|
<span class="hljs-comment">//// DELETE from emails where email LIKE "%jinzhu%";</span>
|
|
|
|
db.Delete(Email{}, <span class="hljs-string">"email LIKE ?"</span>, <span class="hljs-string">"%jinzhu%"</span>)
|
|
<span class="hljs-comment">//// DELETE from emails where email LIKE "%jinzhu%";</span>
|
|
</code></pre>
|
|
<h3 id="soft-delete">Soft Delete</h3>
|
|
<p>If model has <code>DeletedAt</code> field, it will get soft delete ability automatically! then it won't be deleted from database permanently when call <code>Delete</code>, but only set field <code>DeletedAt</code>'s value to current time</p>
|
|
<pre><code class="lang-go">db.Delete(&user)
|
|
<span class="hljs-comment">//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;</span>
|
|
|
|
<span class="hljs-comment">// Batch Delete</span>
|
|
db.Where(<span class="hljs-string">"age = ?"</span>, <span class="hljs-number">20</span>).Delete(&User{})
|
|
<span class="hljs-comment">//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;</span>
|
|
|
|
<span class="hljs-comment">// Soft deleted records will be ignored when query them</span>
|
|
db.Where(<span class="hljs-string">"age = 20"</span>).Find(&user)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;</span>
|
|
|
|
<span class="hljs-comment">// Find soft deleted records with Unscoped</span>
|
|
db.Unscoped().Where(<span class="hljs-string">"age = 20"</span>).Find(&users)
|
|
<span class="hljs-comment">//// SELECT * FROM users WHERE age = 20;</span>
|
|
|
|
<span class="hljs-comment">// Delete record permanently with Unscoped</span>
|
|
db.Unscoped().Delete(&order)
|
|
<span class="hljs-comment">//// DELETE FROM orders WHERE id=10;</span>
|
|
</code></pre>
|
|
<h2 id="associations">Associations</h2>
|
|
<p>By default when creating/updating a record, GORM will save its associations, if the association has primary key, GORM will call <code>Update</code> to save it, otherwise it will be created.</p>
|
|
<pre><code class="lang-go">user := User{
|
|
Name: <span class="hljs-string">"jinzhu"</span>,
|
|
BillingAddress: Address{Address1: <span class="hljs-string">"Billing Address - Address 1"</span>},
|
|
ShippingAddress: Address{Address1: <span class="hljs-string">"Shipping Address - Address 1"</span>},
|
|
Emails: []Email{
|
|
{Email: <span class="hljs-string">"jinzhu@example.com"</span>},
|
|
{Email: <span class="hljs-string">"jinzhu-2@example@example.com"</span>},
|
|
},
|
|
Languages: []Language{
|
|
{Name: <span class="hljs-string">"ZH"</span>},
|
|
{Name: <span class="hljs-string">"EN"</span>},
|
|
},
|
|
}
|
|
|
|
db.Create(&user)
|
|
<span class="hljs-comment">//// BEGIN TRANSACTION;</span>
|
|
<span class="hljs-comment">//// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1");</span>
|
|
<span class="hljs-comment">//// INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1");</span>
|
|
<span class="hljs-comment">//// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);</span>
|
|
<span class="hljs-comment">//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com");</span>
|
|
<span class="hljs-comment">//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com");</span>
|
|
<span class="hljs-comment">//// INSERT INTO "languages" ("name") VALUES ('ZH');</span>
|
|
<span class="hljs-comment">//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 1);</span>
|
|
<span class="hljs-comment">//// INSERT INTO "languages" ("name") VALUES ('EN');</span>
|
|
<span class="hljs-comment">//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2);</span>
|
|
<span class="hljs-comment">//// COMMIT;</span>
|
|
|
|
db.Save(&user)
|
|
</code></pre>
|
|
<p>Refer <a href="associations.html">Associations</a> for more details</p>
|
|
<h3 id="skip-save-associations-when-creatingupdating">Skip Save Associations when creating/updating</h3>
|
|
<p>By default when saving an record, GORM will save its associations also, you could skip it by set <code>gorm:save_associations</code> to <code>false</code></p>
|
|
<pre><code class="lang-go">db.Set(<span class="hljs-string">"gorm:save_associations"</span>, <span class="hljs-literal">false</span>).Create(&user)
|
|
|
|
db.Set(<span class="hljs-string">"gorm:save_associations"</span>, <span class="hljs-literal">false</span>).Save(&user)
|
|
</code></pre>
|
|
<h3 id="skip-save-associations-by-tag">Skip Save Associations by Tag</h3>
|
|
<p>You could use Tag to config your struct to never save an association when creating/updating</p>
|
|
<pre><code class="lang-go"><span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
|
|
gorm.Model
|
|
Name <span class="hljs-keyword">string</span>
|
|
CompanyID <span class="hljs-keyword">uint</span>
|
|
Company Company <span class="hljs-string">`gorm:"save_associations:false"`</span>
|
|
}
|
|
|
|
<span class="hljs-keyword">type</span> Company <span class="hljs-keyword">struct</span> {
|
|
gorm.Model
|
|
Name <span class="hljs-keyword">string</span>
|
|
}
|
|
</code></pre>
|
|
|
|
|
|
</section>
|
|
|
|
</div>
|
|
<div class="search-results">
|
|
<div class="has-results">
|
|
|
|
<h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
|
|
<ul class="search-results-list"></ul>
|
|
|
|
</div>
|
|
<div class="no-results">
|
|
|
|
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<a href="associations.html#association-mode" class="navigation navigation-prev " aria-label="Previous page: Association Mode">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
<a href="crud.html#create" class="navigation navigation-next " aria-label="Next page: Create">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<script>
|
|
var gitbook = gitbook || [];
|
|
gitbook.push(function() {
|
|
gitbook.page.hasChanged({"page":{"title":"CRUD: Reading and Writing Data","level":"1.4","depth":1,"next":{"title":"Create","level":"1.4.1","depth":2,"anchor":"#create","path":"crud.md","ref":"crud.md#create","articles":[]},"previous":{"title":"Association Mode","level":"1.3.3.6","depth":3,"anchor":"#association-mode","path":"associations.md","ref":"associations.md#association-mode","articles":[]},"dir":"ltr"},"config":{"plugins":["github","edit-link"],"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"fontsettings":{"theme":"night","family":"sans","size":2},"github":{"url":"https://github.com/jinzhu/gorm"},"edit-link":{"label":"Edit This Page","base":"https://github.com/jinzhu/gorm/edit/gh-pages/documents/"},"highlight":{},"search":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"title":"GORM Guide","gitbook":"*"},"file":{"path":"crud.md","mtime":"2017-06-11T12:30:57.000Z","type":"markdown"},"gitbook":{"version":"3.2.2","time":"2017-06-11T12:45:12.045Z"},"basePath":".","book":{"language":""}});
|
|
});
|
|
</script>
|
|
</div>
|
|
|
|
|
|
<script src="gitbook/gitbook.js"></script>
|
|
<script src="gitbook/theme.js"></script>
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-github/plugin.js"></script>
|
|
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-edit-link/plugin.js"></script>
|
|
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
|
|
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-search/search.js"></script>
|
|
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
|
|
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
|
|
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-sharing/buttons.js"></script>
|
|
|
|
|
|
|
|
<script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|
|
|