As part of a submission to the MTIP’05 Workshop at the MoDELS 2005 Conference, authors must implement a
mandatory transformation example using their chosen language/tool.
It’s a variant on the usual class-model to relational-model problem, but
there are several problems:
- The specification of the mapping itself is quite convoluted and
unclear (IMO) although thismay well be an illuminating element of
real-world-ness. - The class metamodel has no way to specify association/attribute
multiplicities and the specification does not indicate what they should
default to. - There is only one sample input/output pair and it doesn’t
demonstrate most of the interesting (complicated) aspects that a
transformation should address such as inheritance, class-typed
attributes, transitive primary-/foreign-key aggregation, etc. - The example itself is inconsistent: the resulting relational model
allows for the “address” Association to be many-to-many, but restricts
the “customer” Association to being many-to-one. This fits perfectly
with the semantics of the domain model (an Order can only be associated
with a single Customer, but a Customer may have multiple Addresses), but
this information is neither represented not representable in the input
model so cannot be reflected in the output model.
Leaving these issues aside (although I am surprised that at this late
date no-one else has noticed/commented AFAIK on this last problem), I
applaud the workshop organisers for taking this approach with the
workshop, but am wondering if/how they intend to verify that proposed
solutions do conform to the supplied specification.
Wed, 10 Aug 2005
Tefkat: Sample Solution
The following is a work-in-progress.
I believe it correctly implements the MTIP’05 specification, but
it is not yet extensively tested.
Note, when applied to the sample input, it does not produce the sample output;
it links all three Columns of the Order Table as primary key Columns, thus
allowing an Order to be associated with several Customers.
TRANSFORMATION mtip05_class_to_relational: class -> relational
IMPORT platform:/resource/com.dstc.tefkat.examples/mtip05/models/class.ecore
IMPORT platform:/resource/com.dstc.tefkat.examples/mtip05/models/rdbms.ecore
CLASS ClsToTbl {
Class class;
Table table;
};
CLASS AttrToCol {
Class class;
Attribute attr;
Column col;
};
// ----------------------------------------------------------------------
// Class-typed Attributes and Associations are equivalent
//
PATTERN ClassHasReference(SrcClass, DstClass, RefName)
WHERE Attrs(SrcClass, DstClass, RefName)
OR References(SrcClass, DstClass, RefName)
;
PATTERN Attrs(SrcClass, DstClass, RefName)
FORALL Class SrcClass { attrs: Attribute _ { type: Class DstClass; name: RefName; }; }
;
PATTERN References(SrcClass, DstClass, RefName)
FORALL Association _ { src: SrcClass; dest: DstClass; name: RefName; }
;
// A Class "has" and Attribute for the purposes of the mapping if
// 1. It is directly owned and a primitive type
// 2. A referenced Class (via an Attribute or an Association) "has" the Attribute
// 3. The Class's children "have" the Attribute
//
PATTERN ClassHasAttr(Class, Attr, Name)
WHERE ClassHasSimpleAttr(Class, Attr, Name)
OR ClassHasIncludedAttr(Class, Attr, Name)
OR ClassChildHasAttr(Class, Attr, Name)
;
PATTERN ClassHasSimpleAttr(Class, Attr, Name)
FORALL Class Class {
attrs: Attribute Attr {
type: PrimitiveDataType _PT;
name: Name;
};
}
;
PATTERN ClassHasIncludedAttr(Class, Attr, Name)
FORALL Class Class
WHERE ClassHasReference(Class, Type, RefName)
AND ClassHasAttr(Type, Attr, AttrName)
AND IF Type.is_persistent = true
THEN
Attr.is_primary = true
ENDIF
AND Name = join("_", RefName, AttrName)
;
PATTERN ClassChildHasAttr(Class, Attr, Name)
FORALL Class SubClass
WHERE Class = SubClass.parent
AND ClassHasAttr(SubClass, Attr, Name)
;
PATTERN RootClass(Class, Root)
WHERE IF Parent = Class.parent
THEN
RootClass(Parent, Root)
ELSE
Root = Class
ENDIF
;
// ----------------------------------------------------------------------
// 1. Classes that are marked as persistent in the source model
// should be transformed into a single table of the same
// name in the target model.
//
RULE ClassAndTable(C, T)
FORALL Class C {
is_persistent: true;
name: N;
}
MAKE Table T {
name: N;
}
LINKING ClsToTbl WITH class = C, table = T
;
// Transitively owned Attributes map to Columns
// If the Attribute is primary, so is the corresponding Column
//
RULE MakeColumns
WHERE ClassHasAttr(C, A, N)
AND ClsToTbl LINKS class = C, table = T
MAKE Column Col FROM col(C, N) {
name: N;
type: A.type.name;
}
SET T.cols = Col,
IF A.is_primary = true
THEN
SET T.pkey = Col
ENDIF
LINKING AttrToCol WITH class = C, attr = A, col = Col
;
// References to persistent Classes result in an FKey to
// the corresponding Table.
//
// Columns corresponding to primary Attributes of the target Class
// constitute the corresponding foreign key columns.
//
RULE MakeFKeys
WHERE ClassHasReference(Class, TgtClass, RefName)
AND TgtClass.is_persistent = true
AND RootClass(Class, SrcClass)
AND ClsToTbl LINKS class = SrcClass, table = SrcTable
AND ClsToTbl LINKS class = TgtClass, table = TgtTable
// now determine the foreign key Columns
AND AttrToCol LINKS class = SrcClass, attr = Attr, col = Col
AND Attr.is_primary = true
AND ClassHasAttr(TgtClass, Attr, _)
MAKE FKey FKey FROM fkey(SrcTable, TgtTable, RefName) {
references: TgtTable;
cols: Col;
}
SET SrcTable.fkeys = FKey
;
Post a Comment
You must be logged in to post a comment.