def _identify_relationships(self): ''' Identify relationships in relations Identify relationships by the following steps (1) The relation must have more than one disjoint foreign keys which referencing to identifiers of Entities Let such fkey be E_fkey (2) Examining primary key 1). if pkey has NO E_fkey pkey is a 1:m attribute of A Relationship, whose Identifier is other E_fkey in this relation. The attribute will be assign to the Relationship if exists otherwise the relation unassigned 2). pkey has ONLY E_fkeys if other E_fkeys exists in relation, then relation represents m : 1 Relationship m: Entities whose identifiers are in pkey 1: other E_fkeys If other attributes exists as nonprimes of relation they are m:1 attributes of Relationship If other keys which are not identifiers of Entitiy exists they are 1:1 attributes of Relationship 3). pkey has E_fkeys and other attributes if all-key relation then this represents m:m Relationship with multivalued attributes else unassigned ''' def examine_pkey(pkey, E_fkeys, R): ''' examine pkey, partition pkey into those in E_fkeys and others ''' idr_in_pkey ={fk: R.fkeys[fk].refed_key for fk in E_fkeys if fk.issubset(pkey)} otr_attr = pkey.difference(set([a for fk in idr_in_pkey for a in fk])) return idr_in_pkey, otr_attr # The following assume all identifiers are disjoint # this assumption would be a probem if exists relations referencing to IDD entites # find all Identifiers of Entitnies # relaxed universal assumption, all identifiers are unique all_identifiers = {ent.identifier.elements: name for name, ent in self._entities.items()} # unassigned_attributes unassigned_attributes = {} for name, R in self._R_relations.items(): # find the E_fkeys of relation R pkey = R.pkey E_fkeys = [fk_name for fk_name, fk in R.fkeys.items() if fk.refed_key in all_identifiers] dsj_fkey_count = self._count_disjoint_keys(E_fkeys) # 1) more than one fkeys referencing Entitites if dsj_fkey_count > 1: idr_in_pkey, otr_attr = examine_pkey(pkey, E_fkeys, R) if not idr_in_pkey: # pkey has NO E_fkey R_identifier = frozenset([npa for npa in R.non_primes if frozenset([npa]) in all_identifiers]) otr_non_primes = R.non_primes.difference(R_identifier) if not otr_non_primes: unassigned_attributes.update({R_identifer: pkey}) elif not otr_attr: # 2) only E_fkeys rel = Relationship(name, RelationshipType.regular, frozenset(pkey)) for idr, E_name in all_identifiers.items(): if idr in idr_in_pkey.values(): rel.add_participating_entity(E_name, 'm') for npa in R.non_primes: key = frozenset([npa]) if key in all_identifiers: rel.add_participating_entity(all_identifiers[key], '1') else: attr = Attribute(npa, key, Cardinality.many2one) rel.add_attribute(attr) self._add_relationship(rel, RelationshipType.regular) else: # 3) pkey has other attributes if R.attributes == pkey: # all key relation rel = Relationship(name, RelationshipType.regular, frozenset(pkey)) for idr, E_name in all_identifiers.items(): if idr in idr_in_pkey.values(): rel.add_participating_entity(E_name, 'm') for npa in otr_attr: key = frozenset([npa]) attr = Attribute(npa, key, Cardinality.many2many) rel.add_attribute(attr) self._add_relationship(rel, RelationshipType.regular) else: self._unassigned_relations.append(R) # After determine the main relationships # try to comibine with other E_relations left self._combine_relationship()