在表之间以一对多关系指定主要关系的惯例是什么?

时间:2010-02-07 10:29:26

标签: database database-design one-to-many circular-dependency

我理解如何设计一个在其表之间具有简单一对多关系的数据库模式。我想知道将该集合中的一个特定关系指定为主要关系的惯例或最佳实践。例如,一个人拥有许多信用卡。我知道如何建模。我如何指定其中一张卡作为该人的主要卡?我提出的解决方案充其量只是不够优雅。


我会尽力澄清我的实际情况。 (不幸的是,实际的域名会让事情变得混乱。)我有2个表,每个表都有很多列,让我们说人和任务。我也有Project只有几个属性。一个人有很多项目,但有一个主项目。一个项目有许多任务,但有时有一个主要任务与替代,其他时间没有主要任务,而是一系列任务。没有任何不属于项目的任务,但并未严格禁止。

PERSON (PERSON_ID, NAME, ...)
TASK (TASK_ID, NAME, DESC, EST, ...)
PROJECT (NAME, DESC)

我似乎无法想出一种方法来同时模拟主要项目,主要任务和任务序列,而不会引入过于复杂或纯粹的邪恶。

这是迄今为止我提出的最好的方法:

PERSON (PERSON_ID, NAME, ...)
TASK (TASK_ID, NAME, DESC, EST, ...)
PROJECT (PROJECT_ID, PERSON_FK, TASK_FK, INDEX, NAME, DESC)
PERSON_PRIMARY_PROJECT (PERSON_FK, PROJECT_FK)
PROJECT_PRIMARY_TASK (PROJECT_FK, TASK_FK)

对于一个简单的概念,似乎有太多的表。


我发现这是一个问题,处理非常类似的情况:Database Design: Circular dependency

不幸的是,似乎没有就如何处理这种情况达成共识,“正确”的答案是禁用数据库一致性检查机制。不酷。

4 个答案:

答案 0 :(得分:3)

嗯,在我看来,一个人与CreditCard有两种关系。一个是该人拥有它,另一个是他们认为它是他们的主要信用卡。这告诉我你有一对一和一对多的关系。一对一的回归关系已经存在于CreditCard中,因为它的一对多关系。

这意味着我会将primary_cc_id添加为Person中的字段并单独留下CreditCard。

答案 1 :(得分:2)

两种策略:

  1. 使用位列指示首选卡。
  2. 使用PrefferedCardTable将每个Person与其优先卡的ID相关联。

答案 2 :(得分:0)

一个人可以拥有多张信用卡;然后,您需要在每张信用卡上使用一个标识符来实际将该特定信用卡链接到一个人 - 我认为您已经在您的模型中创建了这种信用卡(某种将该人链接到该信用卡的ID)。

主要信用卡(我假设你的意思是例如作为默认信用卡?)这必须是某种手动操作(例如,你有第三个表,将它们连接在一起)和一个列指定哪一个是默认的。)

Person (SSN, Name)
CreditCard (CCID, AccountNumber)
P_CC (SSN, CCID, NoID)

这意味着,如果您将某人连接到信用卡,则必须指定NoID,如“1”,然后将您的查询设计为默认情况下找到属于此人的信用卡NoID'1'。

这当然只是一种方法,也许你想要限制0,1 - 然后按信用卡添加到该人的日期对它们进行排序。

也许如果你详细说明并提供有关你的专栏和想法的更多信息,那就更容易了。

答案 3 :(得分:0)

所以我在这里尝试使用Northwind和C#Windows App,我只执行了一次查询。

我的代码:

DataClasses1DataContext context = new DataClasses1DataContext();
            DataLoadOptions dlo = new DataLoadOptions();
            dlo.LoadWith<Product>(b => b.Category);
            context.LoadOptions = dlo;

            context.DeferredLoadingEnabled = false;

            context.Log = Console.Out;


            List<Product> test = context.Products.ToList();


            MessageBox.Show(test[0].Category.CategoryName);

结果:

SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued], [t2].[test], [t2].[CategoryID] AS [CategoryID2], [t2].[CategoryName], [t2].[Description], [t2].[Picture]
FROM [dbo].[Products] AS [t0]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t1].[CategoryID], [t1].[CategoryName], [t1].[Description], [t1].[Picture]
    FROM [dbo].[Categories] AS [t1]
    ) AS [t2] ON [t2].[CategoryID] = [t0].[CategoryID]