我正在试图弄清楚如何建模资源的所有权。一个例子可以是信用卡。在某种情况下,信用卡可以由company
,business
或business_admin
拥有,用于支付属于business
的服务。
我想出的是一个表格business_payment
,其中引用了company_payment_method
,business_payment_method
,business_admin_payment_method
以及获得指定付款方式的business
。它们都是可空的,需要触发器来检查插入是否有效 - 在插入之前,一个 ID必须不为null:
CREATE TABLE business_payment (
business_id BIGINT NOT NULL,
CONSTRAINT fk__business_payment__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
company_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__company_payment_method
FOREIGN KEY (company_payment_method_id)
REFERENCES company_payment_method(id)
ON DELETE CASCADE,
business_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_payment_method
FOREIGN KEY (business_payment_method_id)
REFERENCES business_payment_method(id)
ON DELETE CASCADE,
business_admin_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_admin_payment_method
FOREIGN KEY (business_admin_payment_method_id)
REFERENCES business_admin_payment_method(id)
ON DELETE CASCADE
);
临
我在这里看到的优点是,如果删除了任何信用卡,例如
DELETE FROM company_credit_card WHERE id = @companyCreditCardId;
business_payment_method
也会被删除。在应用程序层,没有人必须负责清理它。
Con:
另一方面,我现在有一个具有NULL
值的表格,如果有的话,有一个新实体x_credit_card
我必须将此列添加到此表中,并确保触发器正常工作。
所以这是我正在考虑的解决方案,但我不确定这是否非常优雅 - 特别是因为我正在使用(M * N - M)NULL
条目创建M * N矩阵。
我可以做得比这个设置好吗?
如果你想查看它,下面是完整的代码。不幸的是,由于DELIMITER
这个问题,我不能让它在SQLFiddle上运行。
DROP TABLE IF EXISTS company_business;
DROP TABLE IF EXISTS company_employee;
DROP TABLE IF EXISTS payment_method;
DROP TABLE IF EXISTS business_payment;
DROP TABLE IF EXISTS business_admin_payment_method;
DROP TABLE IF EXISTS company_payment_method;
DROP TABLE IF EXISTS business_payment_method;
DROP TABLE IF EXISTS company;
DROP TABLE IF EXISTS business_admin;
DROP TABLE IF EXISTS business;
CREATE TABLE company (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE business_admin (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE business (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE company_employee (
company_id BIGINT NOT NULL,
CONSTRAINT fk__company_employee__company
FOREIGN KEY (company_id)
REFERENCES company(id)
ON DELETE CASCADE,
business_admin_id BIGINT NOT NULL,
CONSTRAINT fk_company_employee__business_admin
FOREIGN KEY (business_admin_id)
REFERENCES business_admin(id)
ON DELETE CASCADE,
PRIMARY KEY (company_id, business_admin_id)
);
CREATE TABLE company_business (
company_id BIGINT NOT NULL,
CONSTRAINT fk__company_business__company
FOREIGN KEY (company_id)
REFERENCES company(id)
ON DELETE CASCADE,
business_id BIGINT NOT NULL,
CONSTRAINT fk__company_business__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
PRIMARY KEY (company_id, business_id)
);
SET @businessAdminId1 = 1;
INSERT INTO business_admin(id) VALUES (@businessAdminId1);
SET @companyId1 = 1;
INSERT INTO company(id) VALUES (@companyId1);
INSERT INTO company_employee(company_id, business_admin_id) VALUES (@companyId1,@businessAdminId1);
SET @businessId1 = 1;
INSERT INTO business VALUES (@businessId1);
INSERT INTO company_business VALUES(@companyId1, @businessId1);
CREATE TABLE company_payment_method (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
company_id BIGINT NOT NULL,
CONSTRAINT fk__company_payment_method__company
FOREIGN KEY (company_id)
REFERENCES company(id)
ON DELETE CASCADE,
payment_method_token VARCHAR(128) NOT NULL
);
CREATE TABLE business_payment_method (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
business_id BIGINT NOT NULL,
CONSTRAINT fk__business_payment_method__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
payment_method_token VARCHAR(128) NOT NULL
);
CREATE TABLE business_admin_payment_method (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
business_admin_id BIGINT NOT NULL,
CONSTRAINT fk__business_admin_payment_method__business_admin
FOREIGN KEY (business_admin_id)
REFERENCES business_admin(id)
ON DELETE CASCADE,
payment_method_token VARCHAR(128) NOT NULL
);
CREATE TABLE business_payment (
business_id BIGINT NOT NULL,
CONSTRAINT fk__business_payment__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
company_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__company_payment_method
FOREIGN KEY (company_payment_method_id)
REFERENCES company_payment_method(id)
ON DELETE CASCADE,
business_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_payment_method
FOREIGN KEY (business_payment_method_id)
REFERENCES business_payment_method(id)
ON DELETE CASCADE,
business_admin_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_admin_payment_method
FOREIGN KEY (business_admin_payment_method_id)
REFERENCES business_admin_payment_method(id)
ON DELETE CASCADE
);
DELIMITER //
CREATE TRIGGER before_insert_business_payment_method BEFORE INSERT ON business_payment
FOR EACH ROW BEGIN
DECLARE notNullForeignKeyFound BOOLEAN;
DECLARE errorMessage VARCHAR(100);
SET errorMessage = 'Exact one foreign key must be not null!';
SET notNullForeignKeyFound = FALSE;
-- Company credit card ID
IF NEW.company_payment_method_id IS NOT NULL THEN
SET notNullForeignKeyFound = TRUE;
END IF;
-- Business credit card ID
IF NEW.business_payment_method_id IS NOT NULL THEN
IF notNullForeignKeyFound IS TRUE THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errorMessage;
END IF;
SET notNullForeignKeyFound = TRUE;
END IF;
-- Business admin credit card ID
IF NEW.business_admin_payment_method_id IS NOT NULL THEN
IF notNullForeignKeyFound IS TRUE THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errorMessage;
END IF;
SET notNullForeignKeyFound = TRUE;
END IF;
-- Check if at least one ID is not null
IF notNullForeignKeyFound IS FALSE THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errorMessage;
END IF;
END//
DELIMITER ;
SET @companyCreditCardId1 = 1;
INSERT INTO company_payment_method (id, company_id, payment_method_token) VALUES (@companyCreditCardId1, @companyId1, 'wergef');
SET @businessCreditCardId1 = 1;
INSERT INTO business_payment_method (id, business_id, payment_method_token) VALUES (@businessCreditCardId1, @businessId1, 'asjio');
--
-- Here comes the actual action ..
--
-- Succeeds
INSERT INTO business_payment (business_id, business_payment_method_id) VALUES (@businessId1, @companyCreditCardId1);
-- Fails
-- INSERT INTO business_payment (business_id, company_payment_method_id, business_payment_method_id) VALUES (@businessId1, @companyCreditCardId1, @businessCreditCardId1);
-- The following will delete:
-- + business_payment_method.payment_method_id = 1
-- + busuiness_payment_method.payment_method_id = 1
DELETE FROM business_payment_method WHERE id = @companyCreditCardId1;
答案 0 :(得分:1)
另一种方法是让business_entity表具有entity_type(业务,员工,管理员等)。付款可以将单个外键返回给实体。然后,您将获得每个实体类型的详细信息表,其中包含该特定实体类型的详细信息。
business_entity--1----M--business_payment
| |--1-----1--employee
|--1-------1--admin