//
//
//
//
// $Revision$
//
/*
* User: dickon
* Date: 28/07/2006
* Time: 21:55
*
*/
using System;
using SharpDbTools.Connection;
using System.Data;
using System.Data.Common;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Core;
namespace SharpDbTools.Model
{
///
/// Manages a collection of DbModelInfo:
/// - retrieval from files
/// - opening (essentially refreshing) from a database connection
/// - adding for new connection data (name, invariant name, connection string)
/// - saving to files
///
public static class DbModelInfoService
{
static string saveLocation = null;
static object lockObject = new Object();
const string dbFilesDir = "DbTools";
static SortedList cache = new SortedList();
public static IList Names {
get {
return cache.Keys;
}
}
///
///
///
/// The user readable name of the provider
/// the identifying name of the provider
/// the connection string for this connection
///
public static DbModelInfo Add(string name, string invariantName, string connectionString)
{
// TODO: add validation on name; invariant name
// assume that connection string is valid - if it fails an exception will be thrown later
// this allows partially defined connection strings at least to be saved and worked on later
DbModelInfo dbModel = new DbModelInfo(name, invariantName, connectionString);
// add to cache
cache.Add(name, dbModel);
return dbModel;
}
public static void Remove(string name)
{
cache.Remove(name);
}
public static DbModelInfo GetDbModelInfo(string name) {
DbModelInfo modelInfo = null;
bool exists = cache.TryGetValue(name, out modelInfo);
return modelInfo;
}
public static DataTable GetTableInfo(string modelName, string tableName)
{
LoggingService.Debug("-->GetTableInfo");
DbModelInfo modelInfo = GetDbModelInfo(modelName);
DataTable columnTable = modelInfo.Tables[TableNames.Columns];
DataRow[] columnsMetadata = columnTable.Select(ColumnNames.TableName + "='" + tableName + "'");
LoggingService.Debug("found: " + columnsMetadata.Length + " columns belonging to table: " + tableName);
DataTable tableInfo = new DataTable();
DataColumnCollection cols = columnTable.Columns;
foreach (DataColumn c in cols) {
DataColumn nc = new DataColumn(c.ColumnName, c.DataType);
tableInfo.Columns.Add(nc);
}
foreach (DataRow r in columnsMetadata) {
DataRow newRow = tableInfo.NewRow();
newRow.ItemArray = r.ItemArray;
tableInfo.Rows.Add(newRow);
tableInfo.AcceptChanges();
}
return tableInfo;
}
public static DbModelInfo LoadMetadataFromConnection(string name)
{
// get the DbModelInfo
DbModelInfo modelInfo = null;
bool exists = cache.TryGetValue(name, out modelInfo);
if (!exists)
{
// TODO: more detail...
throw new KeyNotFoundException();
}
// get the invariant name and connection string
string invariantName = modelInfo.InvariantName;
string connectionString = modelInfo.ConnectionString;
// get a connection - wait until a connection has been successfully made
// before clearing the DbModelInfo
DbProvidersService factoryService = DbProvidersService.GetDbProvidersService();
DbProviderFactory factory = factoryService.GetFactoryByInvariantName(invariantName);
DbConnection connection = factory.CreateConnection();
modelInfo.ClearMetaData();
// reload the metadata from the connection
// get the Schema table
connection.ConnectionString = connectionString;
connection.Open();
DataTable schemaInfo = connection.GetSchema();
connection.Close();
// clear the DbModelInfo prior to refreshing from the connection
modelInfo.ClearMetaData();
// iterate through the rows in it - the first column of each is a
// schema info collection name that can be retrieved as a DbTable
// Add each one to the DbModel DataSet
foreach (DataRow collectionRow in schemaInfo.Rows) {
String collectionName = (string)collectionRow[0];
DataTable nextMetaData = connection.GetSchema(collectionName);
modelInfo.Merge(nextMetaData);
}
return modelInfo;
}
///
///
///
/// the logical name of the DbModelInfo to save to a file
/// if true, any existing file will be overwritten
/// true if the DbModelInfo was saved, false if not. It will not be saved if
/// either overwriteExistingFile is set to true, and there is an existing file
public static bool SaveToFile(string name, bool overwriteExistingFile)
{
string path = GetSaveLocation();
DbModelInfo modelInfo = null;
cache.TryGetValue(name, out modelInfo);
if (modelInfo != null) {
string modelName = modelInfo.Name;
// write to a file in 'path' called .metadata
// TODO: may want to consider ways of making this more resilient
string filePath = path + @"\" + name + ".metadata";
LoggingService.Debug("writing metadata to: " + filePath);
if (File.Exists(filePath)) {
if (overwriteExistingFile) {
File.Delete(filePath);
} else {
return false;
}
}
using (StreamWriter sw = File.CreateText(filePath)) {
string xml = modelInfo.GetXml();
sw.Write(xml);
sw.Flush();
sw.Close();
return true;
}
} else {
throw new DbModelInfoDoesNotExistException(name);
}
}
public static void SaveAll()
{
foreach (string name in cache.Keys) {
SaveToFile(name, true);
}
}
public static void LoadNamesFromFiles()
{
// load DbModelInfo's from file system
string saveLocation = GetSaveLocation();
LoggingService.Debug("looking for metadata files at: " + saveLocation);
string[] files = Directory.GetFileSystemEntries(saveLocation);
cache.Clear();
for (int i = 0; i < files.Length; i++) {
LoggingService.Debug("found to load metadata from: " + files[i]);
int start = files[i].LastIndexOf('\\');
int end = files[i].LastIndexOf('.');
start++;
string name = files[i].Substring(start, end - start);
DbModelInfo nextModel = new DbModelInfo(name);
cache.Add(nextModel.Name, nextModel);
}
}
public static void LoadFromFiles()
{
// load DbModelInfo's from file system
string saveLocation = GetSaveLocation();
string[] files = Directory.GetFiles(saveLocation);
cache.Clear();
for (int i = 0; i < files.Length; i++) {
DbModelInfo nextModel = LoadFromFileAtPath(@files[i]);
cache.Add(nextModel.Name, nextModel);
}
}
private static DbModelInfo LoadFromFileAtPath(string filePath)
{
LoggingService.Debug("loading DbModelInfo from filePath: " + filePath);
DbModelInfo nextModel = new DbModelInfo();
nextModel.ReadXml(filePath);
return nextModel;
}
public static void LoadFromFile(string logicalConnectionName)
{
LoggingService.Debug("loading DbModelInfo for name: " + logicalConnectionName);
string saveLocation = GetSaveLocation();
string path = saveLocation + "\\" + logicalConnectionName + ".metadata";
DbModelInfo info = LoadFromFileAtPath(path);
cache.Remove(logicalConnectionName);
cache.Add(logicalConnectionName, info);
}
private static string GetSaveLocation()
{
// append the path of the directory for saving Db files
if (saveLocation == null) {
lock(lockObject) {
string configDir = PropertyService.ConfigDirectory;
saveLocation = configDir + @"\" + dbFilesDir;
saveLocation = saveLocation.Replace("/", @"\");
}
}
if (!Directory.Exists(saveLocation)) {
Directory.CreateDirectory(@saveLocation);
}
return saveLocation;
}
}
public class DbModelInfoDoesNotExistException: ApplicationException
{
string name;
public DbModelInfoDoesNotExistException(string dbModelInfoName): base()
{
this.name = dbModelInfoName;
}
public string Name {
get {
return name;
}
}
}
}