sobota, 1 grudnia 2012

Project Integrity Check od środka

Projekt tworzony w programie Enterprise Architect jest przechowywany w formie relacyjnej bazy danych. Bez względu na zastosowany silnik bazodanowy (MS Jet w przypadku plików EAP, MS SQL, MySQL, Oracle czy inny) zastosowany jest ten sam schemat bazy danych do przechowywania modeli. Dane w relacyjnej bazie danych powinny być spójne. Spójność tę można zapewnić w sposób techniczny wprowadzając określone constraints, wówczas silnik baz danych pilnuje zgodności zdefiniowanych reguł.

Funkcja Project Integrity Check

Zapewne kierując się przesłankami wynikającymi z logiki biznesowej dotyczącej przetwarzania danych takich, jak pakiet, element, relacja, atrybut czy metoda, zdecydowano o wdrożeniu wewnątrz programu EA funkcjonalności pozwalającej z poziomu interfejsu użytkownika sprawdzić spójność projektu. Funkcjonalność ta nazywa się Project Integrity Check i jest dostępna poprzez wybór w menu aplikacji opcji Tools -> Data Management -> Project Integrity Check.




Po wywołaniu tej opcji wyświetlane jest następujące okno:
okno Project Integrity Check
Domyślnie zaznaczona jest akcja Report only, dzięki której można zweryfikować poprawność danych bez wprowadzania żadnych zmian. Jeśli zdecydujemy się na automatyczne naprawienie napotkanych problemów należy wybrać Recover/Clean.
W praktyce najpierw należy wykonać pierwszy przebieg w trybie Report only,  a w przypadku odnotowania nieprawidłowości wykonać drugi przebieg naprawczy Report/Clean.

Zakres weryfikacji można modyfikować poprzez zaznaczanie i odznaczanie opcji w sekcji Checks to Run. Jednakże nie widzę powodów, dla których warto byłoby modyfikować domyślne ustawienia.

Przykładowy wynik przedstawia poniższy rysunek.
okno Project Integrity Check - przykładowe wyniki weryfikacji

Przed wykonaniem operacji naprawiającej integralność wyświetlane jest stosowne ostrzeżenie.


W rezultacie akcji wyczyszczenia repozytorium mogą być dane, które zostały uznane za niespójne mogą być usunięte lub odzyskane.
Odzyskane dane są widoczne w oknie Project Browser w specjalnym drzewie o nazwie _recovered_.
Są one podzielone na widoki zawierające osobno diagramy, elementy i pakiety.
Jeśli uznamy, że określone dane należy odzyskać, wówczas można je przenieść do właściwych pakietów.
Jednak jak dotąd nigdy wśród odzyskanych danych nie znalazłem takich, które rzeczywiście zaginęły i wymagałyby odzyskania.

Czy stosować Project Integrity Check?

Twierdzenie, że nie byłem w sytuacji, gdy odzyskałem dane przy użyciu tej funkcjonalności nie znaczy wcale, że nie nie należy jej stosować.
Jeśli repozytorium posiada dane, które nie są spójne program nas nie informuje żadnymi komunikatami o błędach. Po prostu prezentuje nam dane w najlepszy sposób, w jaki potrafi. Zapewne posiada w kodzie mechanizmy, które pozwalają wyświetlić, a nawet modyfikować takie dane. Domyślam się tylko, że niespójność repozytorium może wpływać negatywnie na wydajność, co może być odczuwalne przy bardziej złożonych operacjach, takich jak na przykład Model Compare.

Kiedy należy stosować Project Integrity Check

Przede wszystkim w następujących sytuacjach:
  • Z modelu korzysta wielu użytkowników, których połączenia sieciowe mogą być przerywane. Wystarczy, że jest prawdopodobieństwo, że ktoś bez zamykania projektu wypnie z sieci laptop lub zostanie zerwane połączenie VPN.
  • Model jest skonfigurowany z systemem kontroli wersji. W takim przypadku mamy do czynienia z wieloma operacji importu plików XMI. Zawartość takich plików może pochodzić z innego modelu a połączenie takich danych może skutkować utratą integralności na przykład w zakresie użytych stereotypów, czy relacji do elementów spoza pliku XMI.
  • Model bywa aktualizowany w oparciu o pliki XMI przy użyciu funkcji Import Package from XMI lub Batch XMI Import. Sytuacja jest analogiczna do powyższej.
  • Model jest zintegrowany z innymi aplikacjami/systemami, takimi jak HP Quality Center, Mantis itp.
  • Model jest wykorzystywany przez jednego użytkownika w postaci lokalnego pliku EAP, jednakże podczas wykonywania jakiejś operacji program EA lub system operacyjny uległ awarii.
Z powyższego opisu wynika, że z funkcji tej należy korzystać przede wszystkim w przypadku, gdy mamy do czynienia ze współdzielonym modelem, jak i w przypadku lokalnego projektu opracowywanego przez jedną osobę. Może tylko z tą różnicą, że prawdopodobieństwo wystąpienia niespójności jest wyższe w tym pierwszym przypadku.

Ryzyko stosowania Project Integrity Check

No dobrze, ale skoro przed wykonaniem operacji naprawy spójności danych wyświetlane jest ostrzeżenie, w którym mowa o tym, że może to wnieść znaczące zmiany w modelu, to znaczy, że jest to operacja ryzykowna. Administrator modelu, który naciśnie przycisk OK bierze na siebie odpowiedzialność za zmiany, które zostaną wprowadzone poza jego kontrolą. A co ważniejsze, program nie informuje o tym, których obiektów modelu te zmiany dotyczą! Otrzymujemy tylko informację typu:
  • Invalid connector, a rekomendowaną akcją (tą, która zostanie wykonana) jest - Delete Connector,
  • Orphaned object wraz z akcją: Delete Package Object,
  • 91 Orphaned element stereotypes wraz z akcją: Delete orphaned stereotypes.
Brzmi groźnie....
Ale po pierwsze, jak już wspominałem nie zdarzyło mi się ani odzyskiwać ani utracić żadnych potrzebnych danych. Najczęściej usuwane były tylko jakieś nieaktualne i zagubione obiekty, które zaśmiecały repozytorium i były niewidoczne z poziomu Project Browser lub diagramu.
Po drugie, aby zapobiec niespodziewanemu użyciu tej opcji można włączyć moduł Security i ograniczyć uprawnienia do Project Integrity Check tylko dla określonej grupy użytkowników.
Po trzecie, należy wcześniej wykonać kopię zapasową.

Lista sprawdzeń Project Integrity Check

Jeśli ktoś chce mieć jednak kontrolę nad automatycznymi mechanizmami wykorzystywanymi przez program zamieszczam poniżej zestawienie zapytań SQL, które są wykonywane do sprawdzenia integralności projektu.  Zapytania te są zgodne z MySQL, w przypadku innych silników bazodanowych może być konieczna ich modyfikacja, aby były zgodne z wykorzystywanym dialektem SQL.
W przypadku, gdy EA znajdzie jakieś nieprawidłowości, możemy samodzielnie zmienić zapytanie w taki sposób, aby na przykład zamiast zwracać liczbę (count(*)) zwracało nazwy lub identyfikatory obiektów.

Package Structure

L.p.Zapytanie SQLZnaczenie
1SELECT Count(*) as RecCnt FROM t_package child  LEFT JOIN t_package parent on parent.Package_ID = child.Parent_ID  where parent.Package_ID Is NULL and child.Parent_ID <> 0Zwraca osierocone pakiety, które nie mają pakietu nadrzędnego ani podrzędnego

Object Structure

L.p.Zapytanie SQLZnaczenie
2SELECT     t_diagram.Diagram_ID, t_diagram.Name, t_diagram.ParentID, t_object.Object_ID  FROM         t_diagram LEFT OUTER JOIN t_object ON t_diagram.Package_ID = t_object.Package_ID AND t_diagram.ParentID = t_object.Object_ID  WHERE     (t_object.Object_ID IS NULL) AND (t_diagram.ParentID <> 0)Zwraca osierocone diagramy, które nie są podpięte ani pod żaden pakiet, ani pod żaden element
3SELECT     t_diagram.Diagram_ID, t_diagram.Name, t_diagram.ParentID, 'NULL'  FROM         t_diagram WHERE     t_diagram.ParentID IS NULLInna forma wyszukania diagramów, które powinny być podpięte pod element
4select t_object.Name as OName, t_object.Object_ID as ID  from t_object left join t_package on  t_object.PDATA1 = t_package.Package_ID where  t_package.Package_ID is null and t_object.Object_Type = 'Package'Zwraca elementy typu pakiet, dla których brak odpowiednika w tabeli t_package
5Select t_diagram.Diagram_ID as DiagramID, t_diagram.Name as DiagramName, t_diagram.Diagram_Type as DiagramType from t_diagram left join t_package on t_package.Package_ID = t_diagram.Package_ID where t_package.Package_ID is null or t_package.Parent_ID = 0Również zwraca osierocone diagramy, które nie są podpięte ani pod żaden pakiet, ani pod żaden element
6SELECT t_package.Package_ID, t_package.Name AS PackageName, t_object.Name AS ObjectName FROM t_package LEFT OUTER JOIN t_object ON (Object_Type='Package' AND t_package.Package_ID = t_object.PDATA1) WHERE t_package.Name <> t_object.NameZwraca pakiety, których nazwa różni się od odpowiednika pakietu w tabeli t_object
7SELECT COUNT(*) AS RecCnt FROM t_package WHERE Package_ID = Parent_IDZwraca ilość pakietów, które są nadrzędne wobec samego siebie
8Select count(*) as RecCnt from t_object left  join t_package  on t_package.Package_ID = t_object.Package_ID  where t_package.Package_ID is null and (t_object.ParentID is null or t_object.ParentID=0)Zwraca ilość pakietów, dla których brak odpowiednika w tabeli t_object
9Select count(*) as RecCnt FROM t_object child left join t_object parent  on child.ParentID = parent.Object_ID  where child.ParentID is not null and child.ParentID <> 0 and parent.Object_ID is nullZwraca ilość elementów, które są nadrzędne wobec samego siebie
10Select count(*) as RecCnt FROM t_object where ParentID = Object_IDInna forma powyższego zapytania
11Select count(*) as RecCnt FROM t_object child left join t_object parent on child.ParentID = parent.Object_ID and parent.ParentID = child.Object_ID where parent.Object_ID is not null and child.Object_ID <> child.ParentIDInna forma powyższego zapytania
12Select count(*) as RecCnt FROM t_object child left join t_object parent on child.ParentID = parent.Object_ID where parent.Object_Type = 'Package'Inna forma wyszukania pakietów, które są nadrzędne wobec samego siebie

Objects Features

L.p.Zapytanie SQLZnaczenie
13Select Object_ID, Name FROM t_object where Object_Type is null or Object_Type = '' or ( Name='EA_IMPORT_STUB' and Package_ID=1 and Object_Type='Class')Zwraca elementy, które nie mają określonego typu
14select f.Object_ID, f.FileName from t_objectfiles f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘File’, które nie są przypisane do żadnego elementu
15select f.Object_ID, f.Effort from t_objecteffort f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘Effort’, które nie są przypisane do żadnego elementu
16select f.Object_ID, f.Metric from t_objectmetrics f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘Metric’, które nie są przypisane do żadnego elementu
17select f.Object_ID, f.Problem from t_objectproblems f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘Problem’, które nie są przypisane do żadnego elementu
18select f.Object_ID, f.Requirement from t_objectrequires f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu [internal] ‘Requirement’, które nie są przypisane do żadnego elementu
19select f.Object_ID, f.`Resource` from t_objectresource f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘Resource’, które nie są przypisane do żadnego elementu
20select f.Object_ID, f.Risk from t_objectrisks f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘Risk’, które nie są przypisane do żadnego elementu
21select f.Object_ID, f.Scenario from t_objectscenarios f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘Scenario’, które nie są przypisane do żadnego elementu
22select f.Object_ID, f.Test from t_objecttests f left join t_object o on f.Object_ID = o.Object_ID where o.Object_ID is nullZwraca atrybuty elementu typu ‘Test’, które nie są przypisane do żadnego elementu
23select Object_ID, ConstraintType from t_objectconstraint where ConstraintType is null or ConstraintType=''Zwraca atrybuty elementu typu ‘Constraint’, które nie mają określonego typu
24select Object_ID, `Constraint` from t_objectconstraint where `Constraint` is null or `Constraint`=''Zwraca atrybuty elementu typu ‘Constraint’, które nie mają określonej nazwy
25select Instance_ID, 'Missing Object' as Problem from t_diagramobjects l left join t_object c on l.Object_ID = c.Object_ID where  c.Object_ID is null  UNION select Instance_ID, 'Missing Diagram' as Problem from t_diagramobjects l left join t_diagram d on l.Diagram_ID = d.Diagram_ID where  d.Diagram_ID is nullZwraca brakujące obiekty, które powinny być wyświetlane na diagramach oraz brakujące diagramy, dla których istnieją obiekty do wyświetlenia
26Select child.Object_ID as ID, child.Name as ObjectName, child.Object_Type, parent.Package_ID as PkgID FROM t_object child, t_object parent where child.ParentID = parent.Object_ID and child.Package_ID <> parent.Package_IDZwraca osierocone elementy, które mają wskazany nieprawidłowo element nadrzędny
27select op.* from t_operation op left join t_object obj on op.Object_ID = obj.Object_ID where obj.Object_ID is nullZwraca operacje, które nie są przypisane do żadnego elementu
28select att.* from t_attribute att left join t_object obj on att.Object_ID = obj.Object_ID where obj.Object_ID is nullZwraca atrybuty, które nie są przypisane do żadnego elementu
29select p.* from t_objectproperties p left join t_object o on p.Object_ID = o.Object_ID where o.Object_ID is nullZwraca tagged values, które nie są przypisane do żadnego elementu

All GUIDs

L.p.Zapytanie SQLZnaczenie
30Select * from t_object where ea_guid is nullZwraca elementy, które nie posiadają GUID
31Select * from t_attribute where ea_guid is nullZwraca atrybuty, które nie posiadają GUID
32Select * from t_operation where ea_guid is nullZwraca operacje, które nie posiadają GUID
33Select * from t_attributetag where ea_guid is nullZwraca opisy atrybutów, które nie posiadają GUID
34Select * from t_operationtag where ea_guid is nullZwraca opisy operacji, które nie posiadają GUID
35Select * from t_objectproperties where ea_guid is nullZwraca atrybuty tagged values, które nie posiadają GUID
36Select * from t_diagram where ea_guid is nullZwraca diagramy, które nie posiadają GUID
37Select * from t_operationparams where ea_guid is nullZwraca parametry operacji, które nie posiadają GUID
38Select * from t_package where ea_guid is nullZwraca pakiety, które nie posiadają GUID
39Select * from t_stereotypes where ea_guid is nullZwraca nazwy stereotypów, które nie posiadają GUID
40Select * from t_connector where ea_guid is nullZwraca konektory, które nie posiadają GUID
41Select * from t_connectortag where ea_guid is nullZwraca opisy konektorów, które nie posiadają GUID
42Select * from t_taggedvalue where PropertyID is nullZwraca typy tagged values, które nie posiadają GUID
43select space(40) as ea_guid, space(18) as FieldAlias, space(18)  as TableName, space(11) as FieldName, 0 as Rank
UNION ALL select ea_guid, 'Package GUID' as FieldAlias, 't_package' as TableName, 'ea_guid' as FieldName, 1 as Rank from t_package
UNION ALL select ea_guid, 'Object GUID' as FieldAlias, 't_object' as TableName, 'ea_guid' as FieldName, 2 as Rank from t_object where Object_Type <> 'Package'
UNION ALL select ea_guid, 'Diagram GUID' as FieldAlias, 't_diagram' as TableName, 'ea_guid' as FieldName, 3 as Rank from t_diagram
UNION ALL select ea_guid, 'Stereotype GUID' as FieldAlias, 't_stereotypes' as TableName, 'ea_guid' as FieldName, 4 as Rank from t_stereotypes
UNION ALL select ea_guid, 'Attribute GUID' as FieldAlias, 't_attribute' as TableName, 'ea_guid' as FieldName, 5 as Rank from t_attribute
UNION ALL select ea_guid, 'Operation GUID' as FieldAlias, 't_operation' as TableName, 'ea_guid' as FieldName, 6 as Rank from t_operation
UNION ALL select ea_guid, 'Parameter GUID' as FieldAlias, 't_operationparams' as TableName, 'ea_guid' as FieldName, 7 as Rank from t_operationparams
UNION ALL select ea_guid, 'Connector GUID' as FieldAlias, 't_connector' as TableName, 'ea_guid' as FieldName, 8 as Rank from t_connector
UNION ALL select ea_guid, 'Object Tag GUID' as FieldAlias, 't_objectproperties' as TableName, 'ea_guid' as FieldName, 9 as Rank from t_objectproperties
UNION ALL select ea_guid, 'Connector Tag GUID' as FieldAlias, 't_connectortag' as TableName, 'ea_guid' as FieldName, 10 as Rank from t_connectortag
UNION ALL select ea_guid, 'Attribute Tag GUID' as FieldAlias, 't_attributetag' as TableName, 'ea_guid' as FieldName, 11 as Rank from t_attributetag
UNION ALL select ea_guid, 'Operation Tag GUID' as FieldAlias, 't_operationtag' as TableName, 'ea_guid' as FieldName, 12 as Rank from t_operationtag
UNION ALL select PropertyID as ea_guid, 'Generic Tag GUID' as FieldAlias, 't_taggedvalue' as TableName, 'PropertyID' as FieldName, 13 as Rank from t_taggedvalue
UNION ALL select ea_guid, 'Scenario GUID' as FieldAlias, 't_objectscenarios' as TableName, 'ea_guid' as FieldName, 14 as Rank from t_objectscenarios
ORDER BY 1, 5
Może ktoś podpowie do czego może służyć to zapytanie

Verify Cross References

L.p.Zapytanie SQLZnaczenie
44Select Client, `Type`, Name, Behavior from t_xref where Name in ('Stereotypes', 'CustomProperties') Group by Client, `Type`, Name, Behavior having count(XRefID) >1Zapewne to weryfikacja stereotypów. Ale może ktoś podpowie czego dotyczy ta weryfikacja
45select XrefID from t_xref left outer join t_object on t_xref.Client = t_object.ea_guid where  t_xref.`Type`='element property' and t_xref.Name='Stereotypes' and t_object.ea_guid is null UNION select XrefID from t_xref left outer join t_attribute on t_xref.Client = t_attribute.ea_guid where  t_xref.`Type`='attribute property' and t_xref.Name='Stereotypes' and t_attribute.ea_guid is null UNION select XrefID from t_xref left outer join t_operation on t_xref.Client = t_operation.ea_guid where  t_xref.`Type`='operation property' and t_xref.Name='Stereotypes' and t_operation.ea_guid is null UNION select XrefID from t_xref left outer join t_operationparams on t_xref.Client = t_operationparams.ea_guid where  t_xref.`Type`='parameter property' and t_xref.Name='Stereotypes' and t_operationparams.ea_guid is null UNION select XrefID from t_xref left outer join t_connector on t_xref.Client = t_connector.ea_guid where  t_xref.`Type`='connector property' and t_xref.Name='Stereotypes' and t_connector.ea_guid is null UNION select XrefID from t_xref left outer join t_connector on t_xref.Client = t_connector.ea_guid where  t_xref.`Type`='connectorSrcEnd property' and t_xref.Name='Stereotypes' and t_connector.ea_guid is null UNION select XrefID from t_xref left outer join t_connector on t_xref.Client = t_connector.ea_guid where  t_xref.`Type`='connectorDestEnd property' and t_xref.Name='Stereotypes' and t_connector.ea_guid is nullZwraca listę osieroconoych stereotypów, które nie są wykorzystywane przez elementy, atrybuty, metody, parametry metod lub relacje

Connectors

L.p.Zapytanie SQLZnaczenie
46select count(*) as numrows from t_connector where Connector_Type is nullZwraca liczbę relacji, dla których brakuje typu
47Select t_connector.Connector_ID, t_connector.Connector_Type  from t_connector left join t_object on t_connector.End_Object_ID = t_object.Object_ID where t_object.Object_ID is null or ( t_object.Name='EA_IMPORT_STUB' and t_object.Package_ID=1 and t_object.Object_Type='Class') UNION  Select t_connector.Connector_ID, t_connector.Connector_Type  from t_connector left join t_object on t_connector.Start_Object_ID = t_object.Object_ID where t_object.Object_ID is null or ( t_object.Name='EA_IMPORT_STUB' and t_object.Package_ID=1 and t_object.Object_Type='Class')Zwraca listę relacji, dla których brakuje albo elementu źródłowego albo docelowego
48select Instance_ID, 'Missing Connector' as Problem from t_diagramlinks l left join t_connector c on l.ConnectorID = c.Connector_ID where  c.Connector_ID is null  UNION select Instance_ID, 'Missing Diagram' as Problem from t_diagramlinks l left join t_diagram d on l.DiagramID = d.Diagram_ID where  d.Diagram_ID is nullZwraca listę relacji, które powinny być wyświetlane na diagramach, ale brakuje dla nich relacji w modelu
49select count(*) as RecCount, DiagramID, ConnectorID,'Duplicate Link Information' as Problem  from t_diagramlinks   group by DiagramID, ConnectorID having count(*) > 1Zwraca listę relacji, które są wyświetlane na diagramach, dla których istnieje więcej niż jedna relacja w modelu
50select * from t_connectorconstraint c left join t_connector o on c.ConnectorID = o.Connector_ID where o.Connector_ID is nullZwraca listę ograniczeń przypisanych do relacji, dla których brakuje relacji
51select * from t_connectortag c left join t_connector o on c.ElementID = o.Connector_ID where o.Connector_ID is nullZwraca listę tagów przypisanych do relacji, dla których brakuje relacji
52SELECT t_connector.Connector_ID, t_connector.Connector_Type, t_diagram.Diagram_ID, t_connector.DiagramID FROM t_connector LEFT JOIN t_diagram ON t_connector.DiagramID = t_diagram.Diagram_ID WHERE (((t_diagram.Diagram_ID) Is Null) AND ((t_connector.DiagramID)<>0))Sprawdza spójność pomiędzy relacjami w modelu a relacjami prezentowanymi na diagramach
53SELECT t_connector.Connector_ID, t_connector.SourceRole, t_connector.DestRole, t_connector.StyleEx FROM t_connector, t_operation WHERE t_connector.Start_Object_ID = t_operation.Object_ID AND t_operation.Stereotype = 'FK' GROUP BY Connector_IDWeryfikuje poprawność relacji typu foreign key
54select Connector_ID from t_connector where Connector_Type='Realization'Sprawdza poprawność, bo powinno być ‘Realisation’
55select Stereotype from t_stereotypes where AppliesTo='realization'Sprawdza, czy istnieją stereotypy, które są stosowane do relacji ‘realization’ zamiast ‘realisation’
56select c.* from t_attributeconstraints c left join t_attribute o on c.ID = o.ID where o.ID is nullZwraca listę constraints atrybutów, dla których nie znaleziono atrybutu
57select * from t_attributetag c left join t_attribute o on c.ElementID = o.ID where o.ID is nullZwraca listę tagów atrybutów, dla których nie znaleziono atrybutu
58select * from t_attribute where t_attribute.Name is nullZwraca listę atrybutów bez nazwy
59select o.*, c.OperationID as OpID, c.PostCondition from t_operationposts c left join t_operation o on c.OperationID = o.OperationID where o.OperationID is nullZwraca listę warunków końcowych dla metod, dla których nie znaleziono metody
60select o.*, c.OperationID as OpID, c.PreCondition from t_operationpres c left join t_operation o on c.OperationID = o.OperationID where o.OperationID is nullZwraca listę warunków początkowych dla metod, dla których nie znaleziono metody
61select * from t_operationtag c left join t_operation o on c.ElementID = o.OperationID where o.OperationID is nullZwraca listę tagów metody, dla których nie znaleziono metody
62select c.* from t_operationparams c left join t_operation o on c.OperationID = o.OperationID where o.OperationID is nullZwraca listę parametrów metody, dla których nie znaleziono metody
63select 0 as tabletype, `Type`, Classifier, ea_guid from t_attribute where Classifier is not null and Classifier <> '0' union select 1 as tabletype, `Type`, Classifier, ea_guid from t_operation where Classifier is not null and Classifier <> '0' union select 2 as tabletype, `Type`, Classifier, ea_guid from t_operationparams where Classifier is not null and Classifier <> '0'Może ktoś podpowie do czego to może służyć




1 komentarz: