#region License // Copyright 2005-2019 Paul Kohler (https://github.com/paulkohler/minisqlquery). All rights reserved. // This source code is made available under the terms of the GNU Lesser General Public License v3.0 // https://github.com/paulkohler/minisqlquery/blob/master/LICENSE #endregion using System; using System.Collections.Generic; namespace MiniSqlQuery.Core.DbModel { /// Examins a providing sort methods. public class DbModelDependencyWalker { /// The _model. private readonly DbModelInstance _model; /// Initializes a new instance of the class. /// The database model instance. public DbModelDependencyWalker(DbModelInstance model) { if (model == null) { throw new ArgumentNullException("model"); } _model = model; } /// Sorts the tables by checking the foreign key references recursivly building a list of tables in order. /// An array of tables in dependency order. public DbModelTable[] SortTablesByForeignKeyReferences() { List tables = new List(); // add tables with no FKs foreach (DbModelTable table in _model.Tables) { if (table.ForeignKeyColumns.Count == 0) { tables.Add(table); } } foreach (DbModelTable table in _model.Tables) { ProcessForeignKeyReferences(1, tables, table); } return tables.ToArray(); } /// The process foreign key references. /// The level. /// The tables list. /// The table. /// private void ProcessForeignKeyReferences(int level, List tablesList, DbModelTable table) { if (tablesList.Contains(table)) { return; } // recursive insurance ;-) level++; if (level > 1000) { throw new InvalidOperationException(string.Format("FK processor exceeded recursive level of 1000 at '{0}'.", table.Name)); } // if there are FK refs, add the refered tables first if (table.ForeignKeyColumns.Count > 0) { // if the table is not already in the list.... foreach (DbModelColumn fkColumn in table.ForeignKeyColumns) { // ensure its not a self referencing table if (fkColumn.ForeignKeyReference.ReferenceTable != table) { ProcessForeignKeyReferences(++level, tablesList, fkColumn.ForeignKeyReference.ReferenceTable); } } // now add the table if not in the list yet if (!tablesList.Contains(table)) { tablesList.Add(table); } } } } }