将SQL翻译为OCL?

3

我有一段想要翻译成OCL的SQL代码。由于我不擅长SQL,因此希望通过这种方式提高代码的可维护性。我们使用Interbase 2009、Delphi 2007以及Bold和modeldriven开发。现在我希望在这里找到会说好SQL和OCL的人:-) 原始的SQL代码:

Select Bold_Id, MessageId, ScaniaId, MessageType, MessageTime, Cancellation, ChassieNumber, UserFriendlyFormat, ReceivingOwner, Invalidated, InvalidationReason,
(Select Parcel.MCurrentStates From Parcel
Where ScaniaEdiSolMessage.ReceivingOwner = Parcel.Bold_Id) as ParcelState From ScaniaEdiSolMessage
Where MessageType = 'IFTMBP' and
not Exists (Select * From ScaniaEdiSolMessage EdiSolMsg
Where EdiSolMsg.ChassieNumber = ScaniaEdiSolMessage.ChassieNumber and EdiSolMsg.ShipFromFinland = ScaniaEdiSolMessage.ShipFromFinland and EdiSolMsg.MessageType = 'IFTMBF') and
invalidated = 0 Order By MessageTime desc

经过简化后:

Select Bold_Id, (Select Parcel.MCurrentStates From Parcel 
where ScaniaEdiSolMessage.ReceivingOwner = Parcel.Bold_Id) From ScaniaEdiSolMessage
Where MessageType = 'IFTMBP' and not Exists (Select * From ScaniaEdiSolMessage
EdiSolMsg Where EdiSolMsg.ChassieNumber = ScaniaEdiSolMessage.ChassieNumber and
EdiSolMsg.ShipFromFinland = ScaniaEdiSolMessage.ShipFromFinland and 
EdiSolMsg.MessageType = 'IFTMBF') and invalidated = 0

注意: MessageType有两种情况,'IFTMBP'和'IFTMBF'。

因此,要列出的表是ScaniaEdiSolMessage。它具有以下属性:

  • MessageType: 字符串
  • ChassiNumber: 字符串
  • ShipFromFinland: 布尔值
  • Invalidated: 布尔值

它还与名为ReceivingOwner的表Parcel相关联,其BoldId为关键字。

因此,它似乎列出了ScaniaEdiSolMessage的所有行,然后有一个子查询,也列出了ScaniaEdiSolMessage的所有行,并将其命名为EdiSolMsg。然后排除几乎所有行。实际上,上面的查询从28000条记录中仅返回一个结果。

在OCL中,列出所有实例很容易:

ScaniaEdiSolMessage.allinstances

还可以通过选择过滤行,例如:

ScaniaEdiSolMessage.allinstances->select(shipFromFinland and not invalidated)

但是我不明白如何制作一个OCL来匹配上面的SQL。

4
你在做一些 Scania 卡车的事情?:)我觉得你想做的事情对我来说似乎不太好。首先,SQL 是基于关系代数,而 OCL 是基于面向对象环境中的一阶谓词。这使得它们两者以不同的方式看待世界。例如,简单的导航在 SQL 中是通过选择和连接来实现的,而在 OCL 中则是通过从一个对象到其他对象的关联进行的。面向对象和关系不匹配可能会在未来给你带来很多问题... - Gabriel Ščerbák
是的,应用程序中有一些卡车的东西。许多SQL表达式相对容易转换为OCL,即使后者是面向对象的(OCL也可以过滤事物)。我不知道您在考虑什么样的不匹配问题,但出于简单起见,我希望尽可能多地使用OCL。 - Roland Bengtsson
2
为什么不至少学习一些SQL来维护你已有的内容呢?我同意Gabriel的观点。或许还可以找一个支持OCL语言的数据库,可以替代或与SQL同时使用。 - Stephanie Page
3个回答

3
听听Gabriel和Stephanie的建议,学习更多的SQL。
你说你想让代码更易维护,但理解SQL的开发人员数量远远大于理解OCL的开发人员数量。
如果你明天离开这个项目并将其转换为OCL,能找到能够维护OCL的人的机会非常渺茫。然而,能找到维护SQL的人的机会非常高。
不要因为你擅长使用圆形锤子就试图将方形木棒塞入圆孔中 :)

这只是个人偏好的问题。我们的政策是尽可能使用OCL。选择OCL的原因是它简单易用,并且是Bold框架的基础。但我同意更多的人知道SQL而不是OCL。 - Roland Bengtsson

1

有一个项目,Dresden OCL,可能会对您有所帮助。

Dresden OCL提供了一组工具,用于解析和评估各种模型(如UML、EMF和Java)上的OCL约束。此外,Dresden OCL还提供了用于Java/AspectJ和SQL代码生成的工具。 Dresden OCL的工具可以作为其他项目的库使用,也可以作为插件项目使用,扩展Eclipse的OCL支持。

我没有使用过它,但有一个演示文稿展示了该工具如何从模型和OCL约束生成SQL。我知道您要求相反的操作,但也许通过使用这个工具,您可以找到答案。同样的人还撰写了一篇论文,描述了OCL-> SQL转换。


0

使用MDriven(Delphi的Bold的继承者),我会这样做:

当使用OCL转SQL时,如果您考虑需要检查的不同信息集,则一切都变得更加容易。然后使用OCL运算符- & gt; intersection来查找所需的集合。

因此,在您的情况下,您可能会有一个如下所示的集合:

ScaniaEdiSolMessage.allinstances->select(shipFromFinland and not invalidated)

但你也有这样的一组:

ScaniaEdiSolMessage.allinstances->select(m|m.ReceivingOwner.MessageType = 'IFTMBP')

而且你还有这个标准:

Parcel.allinstances->select(p|p.Messages->exists(m|m.MessageType = 'IFTMBF')).Messages

如果所有这些集合都具有相同的结果类型(ScaniaEdiSolMessage集合),则可以简单地对它们进行交集运算以获得所需的结果。
ScaniaEdiSolMessage.allinstances->select(shipFromFinland and not invalidated)
->intersection(ScaniaEdiSolMessage.allinstances->select(m|m.ReceivingOwner.MessageType = 'IFTMBP'))
->intersection(Parcel.allinstances->select(p|p.Messages->exists(m|m.MessageType = 'IFTMBF')).Messages
    )

而且看着我们可以稍微简化一下:

    ScaniaEdiSolMessage.allinstances
    ->select(m|m.shipFromFinland and (not m.invalidated) and
              (m.ReceivingOwner.MessageType = 'IFTMBP'))
    ->intersection(Parcel.allinstances->select(p|
             p.Messages->exists(m|m.MessageType = 'IFTMBF')).Messages
        )

1
allinstances 不是 OCL 的功能;你可能指的是 allInstances()。 - Ed Willink
加粗可能并没有严格遵循OCL标准,所以allinstances实际上运行良好。这个问题已经超过7年了。快速检查代码发现原始SQL是相同的 :) - Roland Bengtsson
@EdWillink - 您是正确的 - 在 OCL 中,即使方法不接受参数,括号也是必需的。但在 MDriven 实现的 OCL 中,当没有参数时,我们允许省略它们。 - Hans Karlsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接