如何维护一对多关系?(100分)

  • 主题发起人 主题发起人 yysun
  • 开始时间 开始时间
Y

yysun

Unregistered / Unconfirmed
GUEST, unregistred user!
一个表是主表,另一个从表与它有一对多关系。
需要主表中关键字段改变,从表相应的字段也改变,
主表中记录删除,从表相应的记录也删除,
如何实现比较好呢?

 
最简单的办法是DBMS支持级联(Cascade)更新和删除,
具体设置及调用方式可参见你所用的DBMS说明.

如果不能支持,当然只能程序维护了.

删除比较方便,先删子表相应记录,再删主表的记录;

修改麻烦一点,
1. 先对主表插入一条伪(dummy)记录,
2. 将子表中要修改的记录的外码值改为主表的伪记录的相应码值.
3. 而后再修改主表记录,
4. 将子表中要修改的记录的外码值改为需要的外码值
5. 将主表伪记录删除掉

实际上,支持级联更新的DBMS也是这个过程,只是在内部进行而已.
 
谢谢dwwang, 今天您也能闯进来,真行啊!

如果我是两个TTable对付dbase的数据表(*.dbf)有好办法吗?
 
那就只有用我说的第二种办法了,自己的程序来维护。(见上面)

但是现在Internet上数据库控件这么多,是否可以先
搜索一下,有没有能实现此功能的。只要是有源码的,
用起来可以比较放心(当然同时也可以看到它是怎么做的)。
 
为什么要"一条伪(dummy)记录",然后再删除呢?
 
我所说的插入伪记录,是指对于支持Reference Key的DBMS而言。
我回答这个问题时还不知道你使用DBASE,后来也忘记加以说明。

对于支持Reference Key的DBMS,如果不插入伪记录,显然不可
能实现记录码值的修改。因为无论先改主表还是子表都将导致外码冲突。

对于DBASE之类的表(如果不支持外码概念),则通过程序可随
意增删改,只要确保程序逻辑无误就可以了。

咦?转了一圈,我等于什么也没说呀!呜呜呜...(作委屈状)
 
伪记录是数据库自身的解决办法,自己的程序里不用伪记录。

修改主记录前记下主记录的关键字,主记录修改后检查关键字是否改变,如果关键
字改变就到子表中修改外码值等于主记录原关键字的记录,使其外码值与主记录现
关键字相符。

我现在做的系统大多是这种一对多的主从结构,我都是这样解决的。这种情况比较
常见,如果数据库本身不支持,全靠程序来解决会比较烦琐。我忙完这段后会考虑
写个控件解决这一问题。
 
谢谢dwwang和Sunset,
对于不支持关键字的dbase,靠程序解决一对多关系时,再加主关键字唯一性的控制
就更麻烦了.
 
SunSet说的不对呀!

如果你真的在DBMS中定义了外码,你在修改主记录的时候,
如果修改了码值,系统就会出错,因为子表中的记录没有
码值可以参考了,怎么可能允许你修改呢?

例如:

主表中的码值: xxx

子表中的外码值: xxx

如果你想把主表中的码值改为yyy,则子表中的xxx的记录就没有了参照,
系统会拒绝你修改主表中的码值.

反过来,你记住了主表码值xxx,当你知道用户要把它改成yyy时,你想先去
子表中将相应记录改为yyy.但这时候主表中还没有码值yyy的记录,同样违反了
外码规则,系统仍会拒绝.

我们通常戏称为"死锁".

这一点是绝对不可能有别的办法实现的.
(试想一下,DBMS自身可利用的资源与方法比编程者多得多,如果不通过
插入伪记录就能实现,DBMS怎么还会用这种方法呢?)
 
在用DBASE建立关键字可以用写文件(文本文件或数据库)的方法:
每次加入记录则在以前的数字上+1,当然文件开始应该有个0。
我记得有一个控件实现了这个功能可惜没有SOURCE。
 
不知道dwwang兄用什么数据库,小弟现在就用Paradox,反正是没问题。
 
那我就不清楚了,Paradox是不是真支持外码。
“真正的”DBMS都是不行的(SQLServer/SYBASE/ORACLE/...)

不过老兄要编一个支持这种功能的控件,我真得先替老孙谢谢你了:)
这可是功德无量的事儿啊!
 
是啊,肯定会有不少人对Sunset即将出台的这个控件感兴趣的.
 
Sunset的答案尚未等到,其他大虾有维护dbase数据库一对多关系的办法吗?
 
说实话,我觉得编这样一个控件费力不讨好,
什么控件呢? query?table?
用dbedit时如何处理,直接写sql时又怎么处理?

即使支持外码的DBMS,我们有时用try..except去实现,
有时也需要自己编程维护,这要看对界面的要求
和个人的习惯.

因此我觉得用sql语句,插入子表前到主表里去
lookup一下,不是很麻烦.
 
举个例子来说,
用Database Form Expert 生成的 Form上有两个TTable(对付dbase的),
具有一对多关系,主Table做删除和修改主关键字时,对子Table是不负责任的,
在子Table留下了一大堆“无头尸体” :-(

我可以用个TQuery删除这些“无头尸体”,但是得在程序的某个地方启动一下,例如
onFormClose.

想像中如果有个控件,例如TTableBridge,可以设置主Table和子Table List,
根据主Table关键字变化,自动引发子Table的操作 ...

再设想下去,我自己就写成这个控件了 :)
 
刚刚发现的信息,不知yysun是否看过:

http://www.inprise.com/devsupport/bde/bdeapiex/dbidorestructure.html
Examples 9,11

Paradox和DBase7是可以支持外码(主-子表关系)的,
(这样至少解决了 '在子Table留下了一大堆“无头尸体” :-(')

其他的嘛,当然就用程序了,即使SQLServer也是这样的,
我说的那么多终于有用啦!

如果不用PDX或Dbase7,就又没办法了 :-(
 
dwwang,真是非常感谢 .

待我细细看来 ...
 
不好意思,我昨天突然又发现(这哪叫什么发现啊!):
Database Desktop中就是可以定义外码的,因此我提
供的网址不过是定以外码的功能的源程序而已.

因此关键问题还是用不用PDX或DBase7 :-(
 
我是使用 *.dbf, 虽然 BDE 的 Level = 7, 但是,
现有的 .dbf 在 Database Desktop 中显示为
dBase IV Table,所以就找不到定义外码的地方,
paradox table 才有referential integrity 的定义。

我没有用过 dBase 7,还得研究一下:
dBase 7 Table的dBase IV Table差异,如何转换,对现有系统是否有影响。
(但那是另外一个问题了,这个问题可以结束了。)

再次感谢 dwwang,您费心了。
 
后退
顶部