using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using WmData;
using System.Reflection;
using System.Diagnostics;
using System.Text.RegularExpressions;
using MySql.Data.MySqlClient;
namespace WmData {
///
/// WmGenericData: The foundation for object-to-SQL and SQL-to-object systems
/// Created to allow multiple implementations of such systems while maintaining a single interface
/// Created 3rd of August 2010.
///
public abstract class WmGenericData {
protected WmDataIdManager idManager;
protected WmDataBaseCredentials dataBaseCredentials;
protected WmIntermediateObjectManager intermediateObjectManager;
protected WmDataTransactionManager transactionManager;
protected WmDataLink dataLink = null;
public WmGenericData(string databaseUsername, string databasePassword, string databaseHost, int databasePort, string databaseCatalog) {
dataBaseCredentials = new WmDataBaseCredentials(databaseHost, databasePort, databaseUsername, databasePassword, databaseCatalog);
intermediateObjectManager = new WmIntermediateObjectManager(dataBaseCredentials);
reset();
}
public WmGenericData(string databaseUsername, string databasePassword, string databaseHost, int databasePort, string databaseCatalog,string thisServerAddress, ListdataLinkServers, int syncIntervalInSeconds,ListsyncObjectTypes)
: this(databaseUsername,databasePassword,databaseHost,databasePort,databaseCatalog) {
transactionManager = new WmDataTransactionManager(this);
dataLink = new WmDataLink(this,thisServerAddress,dataLinkServers,syncIntervalInSeconds,syncObjectTypes);
dataLink.DataLinkRoleChanged += new WmDataLink.DataLinkRoleChangedEventHandler(dataLink_DataLinkRoleChanged);
}
protected void dataLink_DataLinkRoleChanged(object sender, WmDataLinkRoleChangedEventArguments e) {
if (e.NewDataLinkRole == WmDataLinkRole.ACTIVE) {
// if this data instance becomes active, we should purge the id managers cache to prevent possible
// duplicate id's.
idManager.clearIdManagerCache();
// if this data instance becomes active, we should purge all previous transactions since they may
// include transactions that we're imported from a previous active server that can now become backup (and thus requesting its own transactions)
if (transactionManager != null) {
transactionManager.clearTransactions();
}
}
}
///
/// Data change event handler with the data change event arguments
///
public delegate void DataChangeEventHandler(object sender, WmDataChangeEventArguments e);
///
/// Data change event, fires when something is added, updated or deleted
///
public event DataChangeEventHandler DataChanged;
///
/// Raise a data change event (if someone is listening)
///
protected void raiseDataChangeEvent(string tableName, WmDataRowAction rowAction, int rowId) {
if (DataChanged != null) {
// Trace.WriteLine("WmGenericData: Raising data changed event " + rowAction.ToString() + " table " + tableName + " id " + rowId);
DataChanged(this, new WmDataChangeEventArguments(tableName, rowAction, rowId));
}
}
///
/// Get WmIntermediateObject for the given object type (creates database backend if necessary)
///
protected WmIntermediateObject getIntermediateObject(Type objectType) {
return getIntermediateObject(objectType, true);
}
///
/// Get WmIntermediateObject for the given object type and specify if database should be created
///
protected WmIntermediateObject getIntermediateObject(Type objectType, bool createDatabaseIfNecessary) {
return intermediateObjectManager.getIntermediateObject(objectType,createDatabaseIfNecessary);
}
///
/// Reset the id manager
///
public virtual void reset() {
if (idManager != null) { idManager = null; }
idManager = new WmDataIdManager(dataBaseCredentials);
}
///
/// This is an essential function for any unsafe strings
/// to prevent SQL injections that _are_ possible with DirectData (in comp. to the original data)
///
public string getSafeString(string unsafeString) {
return WmDataTools.getSafeString(unsafeString);
}
#region ADD: addDataRow, importDataRow, addObject
///
/// Add data row
///
public void addDataRow(Type objectType, DataRow newRow) {
addDataRow(objectType, newRow, false);
}
///
/// Add data row and specify override auto id
///
public void addDataRow(Type objectType, DataRow newRow, bool overrideAutoId) {
addDataRow(objectType, newRow, overrideAutoId, -1);
}
///
/// Add data row, specify override auto id and reference transaction moment
///
public abstract void addDataRow(Type objectType, DataRow addRow, bool overrideAutoId, long referenceTransactionMomentUtcTics);
///
/// Import data row, specify override auto id and reference transaction moment
///
public abstract void importDataRow(Type objectType, DataRow importRow, bool overrideAutoId, long referenceTransactionMomentUtcTicks);
///
/// Add object
///
public void addObject(object objectInstance) {
addObject(objectInstance, false);
}
///
/// Add object and specify override auto id
///
public void addObject(object objectInstance, bool overrideAutoId) {
addObject(objectInstance, overrideAutoId, -1);
}
///
/// Add object, specify override auto id and reference transaction moment
///
public abstract void addObject(object objectInstance, bool overrideAutoId, long referenceTransactionMomentUtcTicks);
#endregion
#region UPDATE: updateDataRow, updateObject
///
/// Update data row
///
public void updateDataRow(Type objectType, DataRow updateRow) {
updateDataRow(objectType, updateRow, -1);
}
///
/// Update data row and specify reference transaction moment
///
public abstract void updateDataRow(Type objectType, DataRow updateRow, long referenceTransactionMomentUtcTicks);
///
/// Update object
///
public void updateObject(object objectInstance) {
updateObject(objectInstance, -1);
}
///
/// Update object and specify reference transaction moment
///
public abstract void updateObject(object objectInstance, long referenceTransactionMomentUtcTicks);
#endregion
#region DELETE: deleteDataRow, deleteObject, deleteTableContents
///
/// Delete data row
///
public void deleteDataRow(Type objectType, DataRow deleteRow) {
deleteDataRow(objectType, deleteRow,-1);
}
///
/// Delete data row and specify reference transaction moment
///
public abstract void deleteDataRow(Type objectType, DataRow deleteRow, long referenceTransactionMomentUtcTicks);
///
/// Delete object
///
public void deleteObject(object objectInstance) {
deleteObject(objectInstance, -1);
}
///
/// Delete object matching the given id
///
public void deleteObject(Type objectType, int id) {
deleteObject(objectType, id, -1);
}
///
/// Delete object and specify reference transaction moment
///
public void deleteObject(object objectInstance, long referenceTransactionMomentUtcTicks) {
Type objectType = objectInstance.GetType();
WmIntermediateObject intermediateObject = getIntermediateObject(objectType);
int objectId = (int)intermediateObject.IdProperty.Getter.Invoke(objectInstance);
deleteObject(objectType, objectId, referenceTransactionMomentUtcTicks);
}
///
/// Delete object matching the given id and specify reference transaction moment
///
public abstract void deleteObject(Type objectType, int id, long referenceTransactionMomentUtcTicks);
///
/// Delete table contents (each and every row)
///
public abstract void deleteTableContents(Type objectType);
#endregion
#region GET: getDataRow, getDataRows, getObject, getObjects, getRowCount
///
/// Get data row matching the given id
///
public abstract DataRow getDataRow(Type objectType, int id);
///
/// Get data row matching the select
///
public abstract DataRow getDataRow(Type objectType, string select);
///
/// Get data rows matching the select
///
public DataRow[] getDataRows(Type objectType, string select) {
return getDataRows(objectType, select,null);
}
///
/// Get data rows matching the select, sorted according to the sort string
///
public abstract DataRow[] getDataRows(Type objectType, string select, string sortString);
///
/// Get object matching the given id
///
public abstract object getObject(Type objectType, int id);
///
/// Get object matching the select
///
public abstract object getObject(Type objectType, string select);
///
/// Get objects matching the select
///
public abstract ArrayList getObjects(Type objectType, string select);
///
/// Get the amount of rows (or objects) for the given object type
///
public abstract int getRowCount(Type objectType);
#endregion
///
/// Returns an object by executing an SQL scalar command defined in the selectSql argument
///
///
///
public object getObjectFromSQL(string selectSql) {
object result = null;
MySqlCommand command = new MySqlCommand(selectSql, new MySqlConnection(dataBaseCredentials.getConnectionString()));
try {
command.Connection.Open();
result = command.ExecuteScalar();
} catch (Exception error) {
Trace.WriteLine("WmGenericData: SQL Exception getObjectFromSql(). " + error.Message);
} finally {
command.Connection.Close();
}
return result;
}
///
/// Returns an array of objects as result of SqlCommand (the first column of each return row).
///
///
///
public object[] getObjectsFromSQL(string sqlCommandText) {
List