>本文基于我在理解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中文网其他相关文章!