Best practise for polymorphic associations in MySQL

rat*_*ing 4 mysql inheritance polymorphic-associations

I have a MySQL database with 3 tables holding the main classes of data:

 companies (company_id)
 persons (person_id, company_id) 
 loans (loan_id, company_id) 
Run Code Online (Sandbox Code Playgroud)

Both a 'loan' and a 'person' belong to a company. A company can have loans and a company can have people (such as directors, employees etc.)

There are several scenarios where other data can belong to either a company, a person or a loan, such as 'notes'. For example a user can add a 'note' specific to either a company, a person or a loan.

There are other examples of this such as 'addresses' and 'phone numbers', which can belong to either a company or a person.

I obviously want to have a single table for data such as 'notes', 'addresses' and 'phone numbers', however I am struggling with the best way to link these to companies, people and loans.

Lets use 'notes' as our example here.

Is it better practice to:

1/ Have 3 extra tables linking 'notes' to companies people and loans:

notes(note_id)
persons_notes(person_id, note_id)
companies_notes(company_id, note_id)
loans_notes (loan_id, note_id)

2/ Have a single table 'entities' which has a primary key entity_id used to link all 3 tables:

entities(entity_id)
persons(person_id, entity_id)
companies(company_id, entity_id)
loans (loan_id, entity_id)
notes (note_id, entity_id)
Run Code Online (Sandbox Code Playgroud)

后者在逻辑上有一定道理,但感觉不对,因为个人和公司是与贷款完全不同的一类数据。不知怎的,感觉很脏。

票据和地址将与贷款、个人和公司形成一对多的关系。也就是说,一个公司可能有许多地址或注释。这就是我考虑链接表的原因。

公司可以拥有注册地址和无限的交易地址。一个人可以有当前地址和以前的地址(如果当前地址少于 3 年)。

在这种情况下,拥有贷款(商业贷款)的是公司。人属于公司,通常是公司的董事。因此,一家公司可以有很多人和很多贷款。

  • 一个公司/个人/贷款每个都可以有很多笔记
  • 一个公司/个人可以有多个地址

Vér*_*ace 5

这个问题(以各种形式)经常出现在这个论坛上。

它被称为 EAV(实体属性值)。有充分的理由,它被称为反模式。不使用这种形式的数据模型的原因有很多。它们在此处此处此处进行了概述(以及内的链接 + 查看同一主题中其他海报的回复)。

并非所有人都同意 EAV 总是一件坏事,只是在大多数情况下。Aaron Bertrand(这个小组的一个大人物)写了这篇关于这个问题的帖子。然而,我的建议是坚持传统的设计,并且(可能)让自己的生活更轻松。

为什么不像你描述的那样只有三个主表

  • 公司
  • 贷款

和两个“附属”表

  • 地址
  • 笔记

然后 Person、Company 和 Loan 可以有 Address_id 和 Note_id 字段。不需要复杂的链接表(至少现在还没有:-))。或者首先,您甚至可以在主表中包含注释和地址(如果有一个地址和一个注释 (BLOB) 字段)?

无论您做什么,在您成为经验丰富的数据建模师之前,请避免使用 EAV。ps 欢迎来到论坛!

[编辑]

您能告诉我们您使用的是哪个 RDBMS 吗?可能对我的回复有些影响。这里的版主不喜欢长时间的乒乓式聊天。

我“拼凑”了一个图表和脚本,应该能让你开始。

任何进一步的问题/问题,让我知道。大部分应用程序设计和数据建模都是反复试验——您生成一个数据模型,开始针对它进行编程,然后您会发现您的原始想法无法实现的各种方式。这就是原型设计的目的。给它一个bash,然后解决问题。

在此处输入图片说明

还有那个图表中的脚本。

CREATE TABLE IF NOT EXISTS `mydb`.`Person` (
  `Person_id` INT NOT NULL AUTO_INCREMENT,
  `Name` VARCHAR(45) NOT NULL,
  `Employed_by` INT NULL,
  PRIMARY KEY (`Person_id`))
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS `mydb`.`Loan` (
  `Loan_id` INT NOT NULL AUTO_INCREMENT,
  `Amount` DECIMAL NOT NULL,
  `Other_fields` VARCHAR(45) NULL,
  PRIMARY KEY (`Loan_id`))
ENGINE = InnoDB;





CREATE TABLE IF NOT EXISTS `mydb`.`Person_loan` (
  `Person_id` INT NOT NULL,
  `Loan_id` INT NOT NULL,
  INDEX (`Person_id` ASC),
  INDEX (`Loan_id` ASC),
  INDEX (`Person_id` ASC, `Loan_id` ASC),
  CONSTRAINT `Person_Loan_P_FK`
    FOREIGN KEY (`Person_id`)
    REFERENCES `mydb`.`Person` (`Person_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `Person_Loan_L_FK`
    FOREIGN KEY (`Loan_id`)
    REFERENCES `mydb`.`Loan` (`Loan_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;




CREATE TABLE IF NOT EXISTS `mydb`.`Company` (
  `Company_id` INT NOT NULL AUTO_INCREMENT,
  `Company_name` VARCHAR(45) NULL,
  PRIMARY KEY (`Company_id`))
ENGINE = InnoDB;





CREATE TABLE IF NOT EXISTS `mydb`.`Works_for` (
  `Person_id` INT NULL,
  `Company_id` INT NULL,
  INDEX `Works_For_P_FK_idx` (`Person_id` ASC),
  INDEX `Works_For_C_FK_idx` (`Company_id` ASC),
  CONSTRAINT `Works_For_P_FK`
    FOREIGN KEY (`Person_id`)
    REFERENCES `mydb`.`Person` (`Person_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `Works_For_C_FK`
    FOREIGN KEY (`Company_id`)
    REFERENCES `mydb`.`Company` (`Company_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;




CREATE TABLE IF NOT EXISTS `mydb`.`Company_loan` (
  `Company_id` INT NOT NULL,
  `Loan_id` INT NOT NULL,
  INDEX `Company_loan_C_L_PK` (`Company_id` ASC, `Loan_id` ASC),
  INDEX `Company_Loan_L_FK_idx` (`Loan_id` ASC),
  CONSTRAINT `Company_Loan_C_FK`
    FOREIGN KEY (`Company_id`)
    REFERENCES `mydb`.`Company` (`Company_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `Company_Loan_L_FK`
    FOREIGN KEY (`Loan_id`)
    REFERENCES `mydb`.`Loan` (`Loan_id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;
Run Code Online (Sandbox Code Playgroud)