internal static string GetForeignKeyName(DB3 foreignKey) { ColumnMap foreignKeyMap; string foreignKeyFullName = Text.Unknown; if (!foreignKey.Equals(DB3.Default)) { foreignKeyMap = GetColumnMap(foreignKey); foreignKeyFullName = foreignKeyMap.FullName; } return(foreignKeyFullName); }
internal Relation TryGetRelation(DB3 foreignKey, string method = null) { if (HasIntermediate) { throw new QueryTalkException("Link.TryGetRelation", QueryTalkExceptionType.IntermediateTableDisallowed, String.Format("linked tables = {0}:{1}{2} intermediate table = {3}", DbMapping.GetNodeMap(TableA).Name.Sql, DbMapping.GetNodeMap(TableB).Name.Sql, Environment.NewLine, DbMapping.GetNodeMap(Intermediate).Name.Sql), method); } Relation relation = null; if (foreignKey.Equals(DB3.Default)) { // single relation if (_relations.Count == 1) { return(_relations.First()); } // many relations - missing FK else { throw new QueryTalkException("Link.TryGetRelation", QueryTalkExceptionType.MissingForeignKey, String.Format("linked tables = {0}:{1}", DbMapping.GetNodeMap(TableA).Name.Sql, DbMapping.GetNodeMap(TableB).Name.Sql), method); } } // foreign key is defined: else { relation = _relations.Where(a => a.FKColumns.Contains(foreignKey)) .FirstOrDefault(); if (relation == null) { DbMapping.ThrowForeignKeyNotFoundException(foreignKey, TableA); } } return(relation); }
// builds a relation SQL clause internal static Relation GetRelation(DB3 tableA, DB3 tableB, DB3 foreignKey, string method = null) { var link = TryFindLink(tableA, tableB, method); if (foreignKey.Equals(DB3.Default)) { if (link.HasManyRelations) { throw new QueryTalkException("DbMapping.BuildRelation", QueryTalkExceptionType.MissingForeignKey, String.Format("linked tables = {0}:{1}", GetNodeMap(tableA).Name.Sql, GetNodeMap(tableB).Name.Sql), method); } else { foreignKey = link.DefaultForeignKey; } } return(link.TryGetRelation(foreignKey, method)); }
internal static Link TryFindLink(DB3 tableA, DB3 tableB, string method = null) { var link = GetLink(tableA, tableB); if (link == null && !tableA.Equals(tableB)) { link = TryFindIntermediate(tableA, tableB, method); } // second check if (link == null) { throw new QueryTalkException("DbMapping.TryFindLink", QueryTalkExceptionType.LinkNotFound, String.Format("table A = {0}{1} table B = {2}", DbMapping.GetNodeMap(tableA).Name.Sql, Environment.NewLine, DbMapping.GetNodeMap(tableB).Name.Sql), method); } return(link); }
// returns true if the table is on foreign key side in the relationship internal bool IsFKTable(DB3 table) { return(table.Equals(FKTable)); }
// returns true if the table is on reference side in the relationship internal bool IsRefTable(DB3 table) { return(table.Equals(RefTable)); }
// try find intermediate table & cache it private static Link TryFindIntermediate(DB3 tableA, DB3 tableB, string method = null) { // do not seek for link between the equal tables if (!tableA.Equals(tableB)) { // find all (ordered) links of tableA var linksA = _orderedLinks.Where(a => a.TableA.Equals(tableA)); // find all (ordered) links of tableB var linksB = _orderedLinks.Where(a => a.TableA.Equals(tableB)); // find all intermediate tables var intermediates = (from a in linksA join b in linksB on a.TableB equals b.TableB select a.TableB).ToList(); // enumerate through each intermediate table and evaluate it DB3 c = DB3.Default; // first intermediate DB3 c2 = DB3.Default; // superfluous intermediate (should not exists) foreach (var intermediate in intermediates) { // make sure that the table has been initialized _Invoke(intermediate); // get link C to A var linkToA = _orderedLinks .Where(a => a.TableA.Equals(intermediate) && a.TableB.Equals(tableA)) .Select(a => a.Link) .Distinct() .FirstOrDefault(); // get link C to B var linkToB = _orderedLinks .Where(a => a.TableA.Equals(intermediate) && a.TableB.Equals(tableB)) .Select(a => a.Link) .Distinct() .FirstOrDefault(); // exclude intermediates that have links with many relations if (linkToA.HasManyRelations || linkToB.HasManyRelations) { continue; } // There are 4 combinations of A.C.B relationship: // -------------------------------------------------- // A << C >> B (allowed) // A << C << B (allowed) // A >> C >> B (allowed) // A >> C << B (disallowed) // ------------------------------------------------------------------------- // The intermediate tables that on ONE side of both relations are excluded. // ------------------------------------------------------------------------- if (linkToA.IsRefTable(intermediate) && linkToB.IsRefTable(intermediate)) { continue; } if (c.IsDefault) { c = intermediate; } else { c2 = intermediate; } } // hit if (!c.IsDefault) { // only a single intermediate table is allowed if (c2.IsDefault) { // create and cache the link A:B var link = new Link(tableA, tableB, c); _links.Add(link); return(link); } else { // link ambiguity throw new QueryTalkException("DbMapping.TryFindIntermediate", QueryTalkExceptionType.LinkAmbiguity, String.Format("table A = {0}{1} table B = {2}{3} intermediate 1 = {4}{5} intermediate 2 = {6}", GetNodeMap(tableA).Name.Sql, Environment.NewLine, GetNodeMap(tableB).Name.Sql, Environment.NewLine, GetNodeMap(c).Name.Sql, Environment.NewLine, GetNodeMap(c2).Name.Sql), method).SetObjectName(DbMapping.GetNodeMap(tableA).Name.Sql); } } } // link has not been found throw new QueryTalkException("DbMapping.TryFindIntermediate", QueryTalkExceptionType.LinkNotFound, String.Format("table A = {0}{1} table B = {2}", GetNodeMap(tableA).Name.Sql, Environment.NewLine, GetNodeMap(tableB).Name.Sql), method).SetObjectName(DbMapping.GetNodeMap(tableA).Name.Sql); }