>本文基於我在理解Ecto查詢DSL:基礎知識的Ecto的基礎上的基礎。現在,我將探索ECTO的更高級功能,包括查詢組成,加入和協會,SQL片段注入,顯式鑄造和動態場訪問。
>再次,假定了長生不老藥的基本知識,以及ECTO的基礎知識,我在Ecto庫的簡介中介紹了這一點。
>
>不難想像所有以上三個查詢都可以一起使用,以提供搜索特定用戶的搜索結果。每個都可以與其他查詢一起使用每個應用程序需求,而無需不必要地重複整個代碼庫中查詢的部分。>在查詢時加入非常基本,但我們只是現在介紹它們。之所以這樣做,是因為僅學習加入ECTO並沒有用:我們也需要了解關聯。儘管這些並不難,但它們並不像到目前為止其他主題那麼小。 簡單地說,關聯使開發人員能夠在模型中處理表關係(以外鍵實現)。它們在每個模型的模式中使用has_one/3和has_many/3宏(對於包含其他模型的模型)和ander_to/3宏(對於其他模型與其他模型 - 具有外鍵的模型)定義了它們。 。
查看我們的ectoing應用程序,我們可以看到一個ectoing.user模型與ectoing.message模型之間的關聯的一個示例。 ectoing.user中定義的架構定義以下關聯:
我們可以看到一個用戶有許多消息(ectoing.message),我們正在調用此關聯:消息。
在ectoing.message模型中,我們定義以下關聯關係:<span>SELECT id, username FROM users; </span><span>SELECT id, username FROM users WHERE username LIKE "%tp%"; </span><span>SELECT id, username FROM users WHERE username LIKE "%tp%" LIMIT 10, 0; </span>
>在這裡,我們說的是模型,ectoing.message,屬於ectoing.user模型。我們還將協會命名為:用戶。默認情況下,ECTO將把_ID附加到屬於關聯名稱上,並將其用作外鍵名(因此,在這裡是:user_id)。可以通過指定forefer_key選項手動指定外鍵名,可以覆蓋此默認行為。例如:
>現在讓我們看一下一個簡單的查詢,該查詢使用JOIN來獲取用戶及其消息:
offset <span>= 0 </span>username <span>= <span>"%tp%"</span> </span> <span># Keywords query syntax </span>get_users_overview <span>= from u in Ectoing.User, </span> <span>select: [u.id, u.username] </span> search_by_username <span>= from u in get_users_overview, </span> <span>where: like(u.username, ^username) </span> paginate_query <span>= from search_by_username, </span> <span>limit: 10, </span> <span>offset: ^offset </span> <span># Macro syntax </span>get_users_overview <span>= (Ectoing.User </span><span>|> select([u], [u.id, u.username])) </span> search_by_username <span>= (get_users_overview </span><span>|> where([u], like(u.username, ^username))) </span> paginate_query <span>= (search_by_username </span><span>|> limit(10) </span><span>|> offset(^offset)) </span> Ectoing<span>.Repo.all paginate_query </span>
has_many <span>:messages, Ectoing.Message </span>
belongs_to <span>:user, Ectoing.User </span>
<span># Ectoing.Message </span>belongs_to <span>:user, Ectoing.User, foreign_key: some_other_fk_name </span>
可以使用聯合和預加載函數的組合來完成查詢內的
>加載關聯:<span>SELECT * FROM users u INNER JOIN messages m ON u.id = m.user_id WHERE u.id = 4; </span>
現在,我們在結果中加載了消息關聯:
<span># Keywords query syntax </span>query <span>= from u in Ectoing.User, </span> <span>join: m in Ectoing.Message, on: u.id == m.user_id, </span> <span>where: u.id == 4 </span> <span># Macro syntax </span>query <span>= (Ectoing.User </span><span>|> join(:inner, [u], m in Ectoing.Message, u.id == m.user_id) </span><span>|> where([u], u.id == 4)) </span> Ectoing<span>.Repo.all query </span>
>關聯隱式地加入了我們的主密鑰和外鍵列,因此我們不必指定一個:on子句。從上面,我們還可以看到,在預加載協會方面,它們並不是懶惰的。如果需要,必須明確加載關聯。
><span>[%Ectoing.User{__meta__: #Ecto.Schema.Metadata<:loaded>, </span> <span>firstname: <span>"Jane"</span>, </span> <span>friends_of: #Ecto.Association.NotLoaded<association :friends_of is not loaded>, </span> <span>friends_with: #Ecto.Association.NotLoaded<association :friends_with is not loaded>, </span> <span>id: 4, </span> <span>inserted_at: #Ecto.DateTime<2016-05-15T20:23:58Z>, </span> <span>messages: #Ecto.Association.NotLoaded<association :messages is not loaded>, </span> <span>surname: <span>"Doe"</span>, </span> <span>updated_at: #Ecto.DateTime<2016-05-15T20:23:58Z>, </span> <span>username: <span>"jane_doe"</span>}, </span> <span>%Ectoing.User{__meta__: #Ecto.Schema.Metadata<:loaded>, </span> <span>firstname: <span>"Jane"</span>, </span> <span>friends_of: #Ecto.Association.NotLoaded<association :friends_of is not loaded>, </span> <span>friends_with: #Ecto.Association.NotLoaded<association :friends_with is not loaded>, </span> <span>id: 4, </span> <span>inserted_at: #Ecto.DateTime<2016-05-15T20:23:58Z>, </span> <span>messages: #Ecto.Association.NotLoaded<association :messages is not loaded>, </span> <span>surname: <span>"Doe"</span>, </span> <span>updated_at: #Ecto.DateTime<2016-05-15T20:23:58Z>, </span> <span>username: <span>"jane_doe"</span>}] </span>
例如,讓我們在用戶名字段上執行對案例敏感的搜索:
(以上包含MySQL特定的SQL。如果您使用的是另一個數據庫,則對您不起作用。)
<span>SELECT id, username FROM users; </span><span>SELECT id, username FROM users WHERE username LIKE "%tp%"; </span><span>SELECT id, username FROM users WHERE username LIKE "%tp%" LIMIT 10, 0; </span>
offset <span>= 0 </span>username <span>= <span>"%tp%"</span> </span> <span># Keywords query syntax </span>get_users_overview <span>= from u in Ectoing.User, </span> <span>select: [u.id, u.username] </span> search_by_username <span>= from u in get_users_overview, </span> <span>where: like(u.username, ^username) </span> paginate_query <span>= from search_by_username, </span> <span>limit: 10, </span> <span>offset: ^offset </span> <span># Macro syntax </span>get_users_overview <span>= (Ectoing.User </span><span>|> select([u], [u.id, u.username])) </span> search_by_username <span>= (get_users_overview </span><span>|> where([u], like(u.username, ^username))) </span> paginate_query <span>= (search_by_username </span><span>|> limit(10) </span><span>|> offset(^offset)) </span> Ectoing<span>.Repo.all paginate_query </span>
>顯式鑄造
ecto使用模型的架構定義的另一種方式是,將查詢中的插值表達式自動施放到架構中定義的相應字段類型中。這些插值表達式被施放在與之比較的場的類型上。例如,如果我們有一個查詢片段,例如u.username> ^用戶名,其中u.username定義為字段:用戶名,架構中的字符串,則用戶名變量將被ecto自動施加到字符串。 > 但是,有時,我們並不總是希望eTo將插值表達式施加給定義的字段類型。在其他時候,ECTO將無法推斷出表達式的類型(通常是涉及SQL代碼的片段時)。在這兩種情況下,我們都可以使用類型/2函數來指定表達式及其應施放的類型。
>讓我們以第一個想要將表達式施放到另一種類型的情況下,因為這是更有趣的場景。在我們的ectoing應用程序中,我們使用了ecto.schema.timestamps宏來向我們的每個表添加兩個額外的字段:updated_at and inserted_at。默認情況下,宏將這些字段的類型設置為具有ECTO.DATETIME的類型。現在,如果我們想查看本月註冊了多少用戶,我們可以使用以下簡單查詢:現在,Ecto愉快地接受了查詢。在鑄造操作後,然後將插值的ecto.date表達式轉換為基礎:日期類型,然後讓基礎數據庫(在這種情況下為MySQL)處理日期和dateTime之間的比較。
>讓我們從一起編寫查詢的示例,我們在其中執行了用戶名搜索:
<span>SELECT id, username FROM users; </span><span>SELECT id, username FROM users WHERE username LIKE "%tp%"; </span><span>SELECT id, username FROM users WHERE username LIKE "%tp%" LIMIT 10, 0; </span>
喜歡之後的分頁查詢,我們也可以概括此查詢,以便它可以從給定表中搜索任何字段。這可以通過執行動態字段訪問來完成:
offset <span>= 0 </span>username <span>= <span>"%tp%"</span> </span> <span># Keywords query syntax </span>get_users_overview <span>= from u in Ectoing.User, </span> <span>select: [u.id, u.username] </span> search_by_username <span>= from u in get_users_overview, </span> <span>where: like(u.username, ^username) </span> paginate_query <span>= from search_by_username, </span> <span>limit: 10, </span> <span>offset: ^offset </span> <span># Macro syntax </span>get_users_overview <span>= (Ectoing.User </span><span>|> select([u], [u.id, u.username])) </span> search_by_username <span>= (get_users_overview </span><span>|> where([u], like(u.username, ^username))) </span> paginate_query <span>= (search_by_username </span><span>|> limit(10) </span><span>|> offset(^offset)) </span> Ectoing<span>.Repo.all paginate_query </span>
>當需要動態指定字段時,使用字段/2函數。它的第一個參數是要訪問的字段表,第二個參數是該字段的名稱本身,被指定為原子。使用以上的常規查詢,我們可以將其封裝在函數中,並使用參數從給定查詢中指定的表中搜索任何給定字段。
在這本書和我的上一篇有關ECTO查詢DSL的文章中,我們涵蓋了很多它的功能。提到的功能應涵蓋應用程序中使用ECTO時遇到的絕大多數案例。但是仍然有一些尚未涵蓋的主題(例如查詢前綴)。 ECTO備受期待的2.0版本中還有所有即將推出的新功能,包括子查詢,聚合查詢和多一對一的關聯。這些以及其他不具體特定的ECTO查詢DSL的功能將在以後的文章中介紹 - 請繼續關注!
>我可以使用eTeco執行涉及加入,子查詢和聚合的複雜查詢是的,是的,ecto支持廣泛的查詢操作,包括加入,子查詢和聚合。您可以使用JOIN關鍵字加入表,從關鍵字創建子征服,以及諸如SUM,AVG,MIN和MAX之類的功能來執行聚合。這使ECTO成為以復雜方式查詢數據的強大工具。
>
> ecto如何處理遷移? ecto提供了一個可靠的遷移系統,允許您創建,修改和刪除數據庫表中的數據庫表一種受控和可逆的方式。您可以使用混合任務生成遷移文件,然後使用ECTO的DSL來定義遷移文件中的更改。
>我可以使用ECTO執行RAW SQL查詢嗎?高級,抽象的編寫查詢方式,您也可以使用ecto.adapters.sql.query函數在需要時執行RAW SQL查詢。
> ecto如何處理schemaless詢問? ECTO提供了一個ecto.query.api.Dynamic函數,可讓您動態構建查詢,而無需預定義的架構。當您需要根據用戶輸入或其他運行時數據構建查詢時,這可能很有用。以上是elixir octo查詢DSL:超越基礎知識的詳細內容。更多資訊請關注PHP中文網其他相關文章!