17、Ecto 中多态关联的创建与 IEx 优化

Ecto 中多态关联的创建与 IEx 优化

1. 多态关联的创建方法

在数据建模中,有时需要将一个记录关联到多个不同类型的记录,这就涉及到多态关联。下面介绍三种创建多态关联的方法。

1.1 方法一:使用多个外键
  • 优点 :这可能是最简单的方法,代码阅读者也容易理解。
  • 缺点
    • 会产生未使用的外键列。笔记表需要为每个可关联的不同表设置外键字段,但单个笔记记录只能关联到另一个记录,所以对于任何给定的笔记记录,只有一个外键列会有值。如果要关联的表数量很多,会变得难以管理。
    • 需要考虑数据完整性。笔记表中的外键字段必须允许为空值,但如果所有字段都为空或两个以上字段不为空,则是不正确的。
  • 解决方案 :可以在笔记模式中添加自定义验证,确保只有一个字段被填充。如果使用支持检查约束的数据库,在创建表时添加约束。例如,使用 Postgres 时,可以在迁移文件中添加以下代码:
priv/repo/migrations/20180620125250_add_notes_tables.exs
fk_check = """
(CASE WHEN artist_id IS NULL THEN 0 ELSE 1 END) +
(CASE WHEN album_id IS NULL THEN 0 ELSE 1 END) +
(CASE WHEN track_id IS NULL THEN 0 ELSE 1 END) = 1
"""
create constraint(:notes_with_fk_fields, :only_one_fk, check: fk_check)
  • 适用场景 :通常是最佳方法,但如果要关联的表数量达到几十个或更多,可能需要考虑其他方法。
1.2 方法二:使用抽象模式
  • 操作步骤
    • 创建迁移文件 :为每个关联的表创建单独的笔记表。
priv/repo/migrations/20180620125250_add_notes_tables.exs
create table(:notes_for_artists) do
  add :note, :text, null: false
  add :author, :string, null: false
  add :assoc_id, references(:artists)
  timestamps()
end
create table(:notes_for_albums) do
  add :note, :text, null: false
  add :author, :string, null: false
  add :assoc_id, references(:albums)
  timestamps()
end
create table(:notes_for_tracks) do
  add :note, :text, null: false
  add :author, :string, null: false
  add :assoc_id, references(:tracks)
  timestamps()
end
- **定义抽象模式**:创建一个共享的模式结构体。
lib/music_db/note.ex
schema "abstract table: notes" do
  field :note, :string
  field :author, :string
  field :assoc_id, :integer
  timestamps()
end
- **建立关联**:在每个关联的模式定义中添加关联。
# lib/music_db/artist.ex
has_many :notes, {"notes_for_artists", MusicDB.Note}, foreign_key: :assoc_id
# lib/music_db/album.ex
has_many :notes, {"notes_for_albums", MusicDB.Note}, foreign_key: :assoc_id
# lib/music_db/track.ex
has_many :notes, {"notes_for_tracks", MusicDB.Note}, foreign_key: :assoc_id
  • 优点 :避免了第一种方法中大量未使用的列,表设计更清晰。
  • 缺点
    • 笔记的列需要在每个关联表中重复。如果要添加或删除列,必须确保同时更改所有表。
    • 不能直接创建笔记记录,必须从父记录开始,使用 build_assoc cast_assoc put_assoc 来创建子记录。
1.3 方法三:使用多对多关联
  • 操作步骤
    • 创建笔记表
priv/repo/migrations/20180620125250_add_notes_tables.exs
create table(:notes_with_joins) do
  add :note, :text, null: false
  add :author, :string, null: false
  timestamps()
end
- **创建连接表**:
priv/repo/migrations/20180815192832_add_notes_join_tables.exs
create table(:artists_notes) do
  add :artist_id, references(:artists)
  add :note_id, references(:notes_with_joins)
end
create index(:artists_notes, :artist_id)
create index(:artists_notes, :note_id)
create table(:albums_notes) do
  add :album_id, references(:albums)
  add :note_id, references(:notes_with_joins)
end
create index(:albums_notes, :album_id)
create index(:albums_notes, :note_id)
create table(:tracks_notes) do
  add :track_id, references(:tracks)
  add :note_id, references(:notes_with_joins)
end
create index(:tracks_notes, :track_id)
create index(:tracks_notes, :note_id)
- **设置笔记模式**:
lib/music_db/note.ex
schema "notes_with_joins" do
  field :note, :string
  field :author, :string
  many_to_many :artists, MusicDB.Artist, join_through: "artists_notes"
  many_to_many :albums, MusicDB.Album, join_through: "albums_notes"
  many_to_many :tracks, MusicDB.Track, join_through: "tracks_notes"
  timestamps()
end
- **添加关联到其他模式**:
# lib/music_db/artist.ex
many_to_many :notes, MusicDB.Note, join_through: "artists_notes"
# lib/music_db/album.ex
many_to_many :notes, MusicDB.Note, join_through: "albums_notes"
# lib/music_db/track.ex
many_to_many :notes, MusicDB.Note, join_through: "tracks_notes"
  • 优点 :解决了前两种方法的一些缺点,关联定义在单独的表中,但只需要一个笔记表,无需担心在多个表中重复列定义。
  • 缺点
    • “多对多”在这种情况下是个误称,单个笔记不应关联到多个记录,但使用多对多关联会使这种情况成为可能,需要确保代码不会意外关联。
    • 由于 has_many many_to_many 的差异,不能以最直观的方式处理关联。
2. 三种方法对比
方法 优点 缺点 适用场景
多个外键 简单易理解 产生未使用外键列,需考虑数据完整性 关联表数量较少
抽象模式 表设计清晰 列重复,不能直接创建记录 关联表数量适中
多对多关联 避免列重复 可能关联多个记录,操作不直观 关联表数量较多
3. 多态关联创建流程
graph LR
    A[选择关联方法] --> B{关联表数量少?}
    B -- 是 --> C[多个外键]
    B -- 否 --> D{关联表数量适中?}
    D -- 是 --> E[抽象模式]
    D -- 否 --> F[多对多关联]
4. IEx 优化建议

Elixir 的交互式控制台 IEx 为使用 Ecto 的项目提供了便捷的数据查询和修改方式。而且,IEx 具有可定制性,通过 .iex.exs 文件可以设置常用的导入、别名、变量或函数,从而简化操作,节省输入时间。

4.1 添加导入和别名
  • 添加别名 :为常用的模块添加别名,减少输入量。例如,对于 MusicDB 应用,可以这样设置:
priv/examples/optimizing_iex.exs
alias MusicDB.{
  Repo,
  Artist,
  Album,
  Track,
  Genre,
  Log
}

这样,原本需要输入 album = MusicDB.Repo.get(MusicDB.Album, 1) |> MusicDB.Repo.preload(:tracks) ,现在只需输入 album = Repo.get(Album, 1) |> Repo.preload(:tracks)
- 导入 Ecto.Query 模块 :在 IEx 中尝试查询时需要使用该模块。可以使用 import_if_available 避免因模块不可用而报错。
- 若偏好查询的关键字语法,可只导入 from 函数:

import_if_available Ecto.Query, only: [from: 2]
- 若偏好宏语法,则需要导入整个模块:
import_if_available Ecto.Query
  • 导入 Ecto.Changeset 模块 :如果需要在 IEx 中修改数据,导入该模块可获得重要的 change cast 函数以及验证和其他实用工具。
import_if_available Ecto.Changeset
4.2 添加辅助函数

可以在 .iex.exs 文件中定义辅助函数,简化常见操作。

  • 更新记录的辅助函数 :创建一个辅助函数来处理更新记录的大部分样板代码。
priv/examples/optimizing_iex.exs
defmodule H do
  def update(schema, changes) do
    schema
    |> Ecto.Changeset.change(changes)
    |> Repo.update
  end
end

使用示例:

artist = Repo.get_by(Artist, name: "Miles Davis")
H.update(artist, name: "Miles Dewey Davis III", birth_date: ~D[1926-05-26])

需要注意的是,这种方法在开发环境中可行,但在生产环境中使用时需要更谨慎,因为没有进行验证和约束检查,可能会引入不良数据。

  • 加载专辑及其曲目 :添加一个函数来一次性加载专辑并预加载其曲目。
defmodule H do
  def load_album(id) do
    Repo.get(Album, id) |> Repo.preload(:tracks)
  end
  def load_album(title) when is_binary(title) do
    Repo.get_by(Album, title: title) |> Repo.preload(:tracks)
  end
end
5. IEx 优化步骤总结
步骤 操作内容 代码示例
1 添加模块别名 alias MusicDB.{Repo, Artist, Album, Track, Genre, Log}
2 导入 Ecto.Query 模块 import_if_available Ecto.Query, only: [from: 2] import_if_available Ecto.Query
3 导入 Ecto.Changeset 模块 import_if_available Ecto.Changeset
4 定义辅助函数 defmodule H do def update(schema, changes) ... end
6. IEx 优化流程
graph LR
    A[启动 IEx 优化] --> B[添加模块别名]
    B --> C{是否需要查询操作?}
    C -- 是 --> D[导入 Ecto.Query]
    C -- 否 --> E{是否需要修改数据?}
    D --> E
    E -- 是 --> F[导入 Ecto.Changeset]
    E -- 否 --> G[定义辅助函数?]
    F --> G
    G -- 是 --> H[定义常用辅助函数]
    G -- 否 --> I[完成优化]
    H --> I

综上所述,在 Ecto 中创建多态关联有多种方法可供选择,应根据关联表的数量和具体需求来决定。同时,通过优化 IEx 可以提高开发效率,使数据查询和修改操作更加便捷。合理运用这些技巧,能让开发工作更加高效和轻松。

【轴承故障诊断】基于融合鱼鹰和柯西变异的麻雀优化算法OCSSA-VMD-CNN-BILSTM轴承诊断研究【西储大学数据】(Matlab代码实现)内容概要:本文提出了一种基于融合鱼鹰和柯西变异的麻雀优化算法(OCSSA)优化变分模态分解(VMD)参数,并结合卷积神经网络(CNN)双向长短期记忆网络(BiLSTM)的轴承故障诊断模型。该方法利用西储大学公开的轴承数据集进行验证,通过OCSSA算法优化VMD的分解层数K和惩罚因子α,有效提升信号分解精度,抑制模态混叠;随后利用CNN提取故障特征的空间信息,BiLSTM捕捉时间序列的动态特征,最终实现高精度的轴承故障分类。整个诊断流程充分结合了信号预处理、智能优化深度学习的优势,显著提升了复杂工况下轴承故障诊断的准确性鲁棒性。; 适合人群:具备一定信号处理、机器学习及MATLAB编程基础的研究生、科研人员及从事工业设备故障诊断的工程技术人员。; 使用场景及目标:①应用于旋转机械设备的智能运维故障预警系统;②为轴承等关键部件的早期故障识别提供高精度诊断方案;③推动智能优化算法深度学习在工业信号处理领域的融合研究。; 阅读建议:建议读者结合MATLAB代码实现,深入理解OCSSA优化机制、VMD参数选择策略以及CNN-BiLSTM网络结构的设计逻辑,通过复现实验掌握完整诊断流程,并可进一步尝试迁移至其他设备的故障诊断任务中进行验证优化
内容概要:本文档《统信服务器操作系统行业版安全加固指导》针对统信UOS(服务器行业版)操作系统,提供了全面的安全配置加固措施,涵盖身份鉴别、访问控制、安全审计、入侵防范、可信验证和数据传输保密性六大方面。文档依据国家等级保护三级标准制定,详细列出了58项具体的安全加固项,包括账户锁定策略、密码复杂度要求、SSH安全配置、日志审计、文件权限控制、系统服务最小化、防止IP欺骗、核心转储禁用等内容,并给出了每项配置的操作命令和检查方法,旨在提升主机系统的整体安全性,满足等保合规要求。; 适合人群:系统管理员、信息安全工程师、运维技术人员以及负责统信UOS服务器部署安全管理的专业人员;具备一定的Linux操作系统基础知识和安全管理经验者更为适宜。; 使用场景及目标:①用于统信UOS服务器系统的安全基线配置合规性检查;②指导企业落实网络安全等级保护制度中的主机安全要求;③在系统上线前或安全整改过程中实施安全加固,防范未授权访问、信息泄露、恶意攻击等安全风险;④作为安全审计和技术检查的参考依据。; 阅读建议:建议结合实际生产环境逐步实施各项安全配置,操作前做好系统备份测试验证,避免影响业务正常运行;同时应定期复查配置有效性,关注系统更新带来的安全策略变化,确保长期符合安全基线要求。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值