Перевести SQL в OCL?

У меня есть кусок SQL, который я хочу перевести в OCL. Я плохо разбираюсь в SQL, поэтому я хочу повысить удобство обслуживания. Мы используем Interbase 2009, Delphi 2007 с Bold и разработку на основе моделей. Теперь я надеюсь, что кто-то здесь хорошо говорит и на 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

ПРИМЕЧАНИЕ. Существует 2 случая для MessageType: "IFTMBP" и "IFTMBF".

Таким образом, таблица, которая должна быть указана, — ScaniaEdiSolMessage. Он имеет такие атрибуты, как:

  • Тип сообщения: Строка
  • Номер шасси: строка
  • ShipFromFinland: Boolean
  • Недействительный: логическое значение

Он также имеет ссылку на таблицу Parcel с именем ReceiveOwner с BoldId в качестве ключа.

Таким образом, кажется, что он перечисляет все строки ScaniaEdiSolMessage, а затем имеет подзапрос, который также перечисляет все строки ScaniaEdiSolMessage и называет его EdiSolMsg. Затем он исключает почти все строки. На самом деле запрос выше дает одно попадание из 28000 записей.

В OCL легко перечислить все экземпляры:

ScaniaEdiSolMessage.allinstances

Также легко фильтровать строки, выбирая, например:

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

Но я не понимаю, как мне сделать OCL, чтобы он соответствовал приведенному выше SQL.


person Roland Bengtsson    schedule 10.06.2010    source источник
comment
Вы занимаетесь какими-то вещами с грузовиками Scania? :) То, что вы хотите сделать, мне кажется не очень хорошим. Во-первых, SQL основан на реляционной алгебре, а OCL — на предикатах первого порядка в объектно-ориентированной среде. Это заставляет их обоих смотреть на мир по-разному. Например. простая навигация в SQL заключается в выборе и объединении. В OCL вы проходите через ассоциации от одного объекта к другому. Объектно-ориентированное и реляционное несоответствие может вызвать у вас много проблем в будущем...   -  person Gabriel Ščerbák    schedule 11.06.2010
comment
Да, в приложении есть некоторые вещи для грузовиков. Многие выражения SQL относительно легко перевести в OCL, даже если последний является объектно-ориентированным (OCL также может фильтровать вещи). Я не знаю, о каких проблемах несоответствия вы думаете, но я хочу, чтобы в OCL было как можно больше для простоты.   -  person Roland Bengtsson    schedule 11.06.2010
comment
Почему бы не выучить хотя бы достаточно SQL, чтобы поддерживать то, что у вас есть. Я согласен с Габриэлем. Или, может быть, найти базу данных, которая говорит на OCL вместо/в дополнение к SQL   -  person Stephanie Page    schedule 05.01.2011


Ответы (3)


Послушайте Габриэля и Стефани, узнайте больше о SQL.

Вы заявляете, что хотите сделать код более удобным для сопровождения, но число разработчиков, понимающих SQL, намного больше, чем число разработчиков, понимающих OCL.

Если вы покинете проект завтра после преобразования этого в OCL, шансы, что вы сможете найти кого-то, кто мог бы поддерживать OCL, очень малы. Однако шансы найти кого-то, кто будет поддерживать SQL, очень высоки.

Не пытайтесь вставить квадратный штифт в круглое отверстие только потому, что вы умеете обращаться с круглыми молотками :)

person rcarver    schedule 24.01.2011
comment
Ну это просто вопрос предпочтений. У нас есть политика, которая использует OCL, когда это возможно. Причиной OCL является простота и то, что это основа Bold, которая выходит за рамки. Но я согласен, что больше людей знают SQL, чем OCL. - person Roland Bengtsson; 27.12.2017

Существует проект Dresden OCL, который может вам помочь.

Dresden OCL предоставляет набор инструментов для анализа и оценки ограничений OCL для различных моделей, таких как UML, EMF и Java. Кроме того, Dresden OCL предоставляет инструменты для генерации кода Java/AspectJ и SQL. Инструменты Dresden OCL можно использовать либо как библиотеку для другого проекта, либо как подключаемый модуль, расширяющий Eclipse с поддержкой OCL.

Я не использовал его, но есть демонстрация, показывающая, как Инструмент генерирует SQL из модели и ограничений OCL. Я понимаю, что вы просите об обратном, но, возможно, используя это, вы сможете понять это. Существует также документ, в котором описываются преобразования OCL->SQL. теми же людьми.

person Miroslav Policki    schedule 13.09.2012

С MDriven (преемником Bold для Delphi) я бы сделал это так:

При работе с OCL в SQL все становится проще, если вы думаете о разных наборах информации, которые вам нужно проверить, а затем используете операторы ocl как -> пересечение, чтобы найти набор, который вам нужен.

Итак, в вашем случае у вас может быть такой набор:

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
        )
person Hans Karlsen    schedule 27.12.2017
comment
allinstances не является средством OCL; вы, вероятно, имеете в виду allInstances() - person Ed Willink; 27.12.2017
comment
Жирный шрифт может не строго соответствовать стандарту OCL, поэтому все экземпляры на самом деле работают нормально. Этому вопросу более 7 лет. Быстрая проверка кода показывает, что исходный SQL такой же :) - person Roland Bengtsson; 27.12.2017
comment
@EdWillink - вы правы - скобки в OCL обязательны, даже если метод не принимает аргументы. Однако в реализации OCL с помощью MDriven мы разрешаем опускать их, когда параметры отсутствуют. - person Hans Karlsen; 28.12.2017