using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Reflection;
using System.Data;
using System.Collections;
using MySql.Data.MySqlClient;
namespace WmData {
///
/// WmDirectData: The lean and mean object-to-SQL and SQL-to-object system
/// This special variant of WmGenericData directly interfaces with MySQL.
/// This class was designed for low-footprint applications and high performance data engines (large numbers of records,
/// frequent and complex queries).
/// The ultimate goal is to get this WmDirectData variant interface compatible with the ordinary WmData.
/// Created 10th of july 2009. (interface compatibility reached @ 3rd of August 2010 when updated to comply with WmGenericData)
///
public class WmDirectData : WmGenericData {
public WmDirectData(string databaseUsername, string databasePassword, string databaseHost, int databasePort, string databaseCatalog) : base(databaseUsername,databasePassword,databaseHost,databasePort,databaseCatalog){
Trace.WriteLine("WmDirectData initiated for " + databaseCatalog + " on host " + databaseHost);
}
public WmDirectData(string databaseUsername, string databasePassword, string databaseHost, int databasePort, string databaseCatalog, string thisServerAddress, List dataLinkServers, int syncIntervalInSeconds, ListsyncObjectTypes)
: base(databaseUsername, databasePassword, databaseHost, databasePort, databaseCatalog,thisServerAddress, dataLinkServers,syncIntervalInSeconds,syncObjectTypes) {
Trace.WriteLine("WmDirectData initiated for " + databaseCatalog + " on host " + databaseHost);
}
#region ADD: addDataRow, importDataRow, addObject
///
/// Add data row specify override auto id and reference transaction moment
///
public override void addDataRow(Type objectType, DataRow addRow, bool overrideAutoId, long referenceTransactionMomentUtcTics) {
WmIntermediateObject intermediateObject = getIntermediateObject(objectType, true);
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
MySqlCommand command = WmDataTools.getMySqlInsertCommand(dataBaseCredentials, intermediateObject);
command.Connection = connection;
foreach (WmIntermediateObjectProperty property in intermediateObject.Properties) {
command.Parameters["?" + property.DataName].Value = addRow[property.DataName];
}
if (!overrideAutoId) {
int autoId = idManager.getNewId(intermediateObject.TableName);
command.Parameters["?id"].Value = autoId;
addRow["id"] = autoId;
}
try {
connection.Open();
command.ExecuteNonQuery();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in addDataRow. " + error.Message);
} finally {
connection.Close();
}
raiseDataChangeEvent(intermediateObject.TableName, WmDataRowAction.ADD, (int)addRow["id"]);
if (transactionManager != null) {
transactionManager.registerInsertOrUpdateTransaction(intermediateObject.TableName, addRow, WmDataRowAction.ADD, referenceTransactionMomentUtcTics);
}
}
///
/// Import data row specify override auto id and reference transaction moment
///
public override void importDataRow(Type objectType, DataRow importRow, bool overrideAutoId, long referenceTransactionMomentUtcTicks) {
addDataRow(objectType, importRow, overrideAutoId, referenceTransactionMomentUtcTicks);
}
///
/// Add object specify override auto id and reference transaction moment
///
public override void addObject(object objectInstance, bool overrideAutoId, long referenceTransactionMomentUtcTicks) {
Type objectType = objectInstance.GetType();
WmIntermediateObject intermediateObject = getIntermediateObject(objectType,true);
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
MySqlCommand command = WmDataTools.getMySqlInsertCommand(dataBaseCredentials,intermediateObject);
command.Connection = connection;
foreach (WmIntermediateObjectProperty property in intermediateObject.Properties) {
command.Parameters["?"+property.DataName].Value = property.Getter(objectInstance);
}
if (!overrideAutoId) {
int autoId = idManager.getNewId(intermediateObject.TableName);
command.Parameters["?id"].Value = autoId;
intermediateObject.IdProperty.Setter(objectInstance, autoId);
}
try {
connection.Open();
command.ExecuteNonQuery();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in addObject. " + error.Message);
} finally {
connection.Close();
}
int givenId = (int)intermediateObject.IdProperty.Getter.Invoke(objectInstance);
raiseDataChangeEvent(intermediateObject.TableName, WmDataRowAction.ADD, givenId);
if (transactionManager != null) {
transactionManager.registerInsertOrUpdateTransaction(intermediateObject, givenId, WmDataRowAction.ADD, objectInstance, referenceTransactionMomentUtcTicks);
}
}
#endregion
#region UPDATE: updateDataRow, updateObject
///
/// Update data row and specify reference transaction moment
/// >
public override void updateDataRow(Type objectType, DataRow updateRow, long referenceTransactionMomentUtcTicks) {
WmIntermediateObject intermediateObject = getIntermediateObject(objectType, true);
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
MySqlCommand command = WmDataTools.getMySqlUpdateCommand(dataBaseCredentials, intermediateObject);
command.Connection = connection;
foreach (WmIntermediateObjectProperty property in intermediateObject.Properties) {
command.Parameters["?" + property.DataName].Value = updateRow[property.DataName];
}
try {
connection.Open();
command.ExecuteNonQuery();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in updateDataRow. " + error.Message);
} finally {
connection.Close();
}
raiseDataChangeEvent(intermediateObject.TableName, WmDataRowAction.UPDATE, (int)updateRow["id"]);
if (transactionManager != null) {
transactionManager.registerInsertOrUpdateTransaction(intermediateObject.TableName, updateRow, WmDataRowAction.UPDATE, referenceTransactionMomentUtcTicks);
}
}
///
/// Update object and specify reference transaction moment
///
public override void updateObject(object objectInstance, long referenceTransactionMomentUtcTicks) {
Type objectType = objectInstance.GetType();
WmIntermediateObject intermediateObject = getIntermediateObject(objectType, true);
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
MySqlCommand command = WmDataTools.getMySqlUpdateCommand(dataBaseCredentials, intermediateObject);
command.Connection = connection;
foreach (WmIntermediateObjectProperty property in intermediateObject.Properties) {
command.Parameters["?" + property.DataName].Value = property.Getter(objectInstance);
}
try {
connection.Open();
command.ExecuteNonQuery();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in updateObject. " + error.Message);
} finally {
connection.Close();
}
int objectId = (int)intermediateObject.IdProperty.Getter.Invoke(objectInstance);
raiseDataChangeEvent(intermediateObject.TableName, WmDataRowAction.UPDATE, objectId);
if (transactionManager != null) {
transactionManager.registerInsertOrUpdateTransaction(intermediateObject, objectId, WmDataRowAction.UPDATE, objectInstance, referenceTransactionMomentUtcTicks);
}
}
#endregion
#region DELETE: deleteDataRow, deleteObject, deleteTableContents
///
/// Delete a data row and specify the reference transaction moment
///
public override void deleteDataRow(Type objectType, DataRow deleteRow, long referenceTransactionMomentUtcTicks) {
WmIntermediateObject intermediateObject = getIntermediateObject(objectType, true);
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
MySqlCommand command = WmDataTools.getMySqlDeleteCommand(dataBaseCredentials, intermediateObject);
command.Connection = connection;
int objectId = (int)deleteRow["id"];
command.Parameters["?id"].Value = objectId;
try {
connection.Open();
command.ExecuteNonQuery();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in deleteDataRow. " + error.Message);
} finally {
connection.Close();
}
raiseDataChangeEvent(intermediateObject.TableName, WmDataRowAction.DELETE, objectId);
if (transactionManager != null) {
transactionManager.registerDeleteTransaction(intermediateObject.TableName, objectId, referenceTransactionMomentUtcTicks);
}
}
///
/// Delete the object with the given object id and specify the reference transaction moment
///
public override void deleteObject(Type objectType, int objectId, long referenceTransactionMomentUtcTicks) {
WmIntermediateObject intermediateObject = getIntermediateObject(objectType,true);
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
MySqlCommand command = WmDataTools.getMySqlDeleteCommand(dataBaseCredentials, intermediateObject);
command.Connection = connection;
command.Parameters["?id"].Value = objectId;
try {
connection.Open();
command.ExecuteNonQuery();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in deleteObject. " + error.Message);
} finally {
connection.Close();
}
raiseDataChangeEvent(intermediateObject.TableName, WmDataRowAction.DELETE, objectId);
if (transactionManager != null) {
transactionManager.registerDeleteTransaction(intermediateObject.TableName,objectId, referenceTransactionMomentUtcTicks);
}
}
///
/// Delete table contents (each and every row)
///
public override void deleteTableContents(Type objectType) {
WmIntermediateObject intermediateObject = getIntermediateObject(objectType, true);
string sqlCommandText = "DELETE FROM "+SqlCatalogName+"." + intermediateObject.TableName;
object emptyReturnObject = getObjectFromSQL(sqlCommandText); // this actually performs the delete query
}
#endregion
#region GET: getDataRow, getDataRows, getObject, getObjects
///
/// Get a data row matching the given id
///
public override DataRow getDataRow(Type objectType, int id) {
string select = "id=" + id;
return getDataRow(objectType, select);
}
///
/// Get a data row matching the select
///
public override DataRow getDataRow(Type objectType, string select) {
DataRow resultRow = null;
DataRow[] resultRows = getDataRows(objectType, select);
if (resultRows.Length > 0) {
resultRow = resultRows[0];
}
return resultRow;
}
///
/// Get data rows matching the select, sorted using the specified sort string
///
public override DataRow[] getDataRows(Type objectType, string select, string sortString) {
DataRow[] returnRows = null;
WmIntermediateObject intermediateObject = getIntermediateObject(objectType, true);
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
string cmdText = "SELECT * FROM " + dataBaseCredentials.Catalog + "." + intermediateObject.TableName;
if (!String.IsNullOrEmpty(select)) {
cmdText += " WHERE " + select;
}
if (!String.IsNullOrEmpty(sortString)) {
cmdText += " ORDER BY " + sortString;
}
MySqlCommand command = new MySqlCommand(cmdText, connection);
try {
connection.Open();
MySqlDataReader reader = command.ExecuteReader();
DataTable dataTable = intermediateObject.DataTable;
Stopwatch stopwatch = Stopwatch.StartNew();
dataTable.Load(reader);
stopwatch.Stop();
Trace.WriteLine("WmDirectData: getDataRows() objectType " + objectType.ToString() + " dataTable.Load(reader) took " + stopwatch.ElapsedMilliseconds + " ms.");
stopwatch.Reset();
stopwatch.Start();
returnRows = dataTable.Select(null, sortString);
Trace.WriteLine("WmDirectData: getDataRows() objectType " + objectType.ToString() + " dataTable.Select() took " + stopwatch.ElapsedMilliseconds + " ms.");
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in getDataRows. " + error.Message);
} finally {
connection.Close();
}
return returnRows;
}
///
/// Get object matching the specified id
///
public override object getObject(Type objectType, int id) {
string select = "id=" + id;
return getObject(objectType, select);
}
///
/// Get object matching the select
///
public override object getObject(Type objectType, string select) {
ArrayList tmpRes = getObjects(objectType, select);
if (tmpRes.Count > 0) {
return tmpRes[0];
} else {
return null;
}
}
///
/// Get objects matching the select
///
public override ArrayList getObjects(Type objectType, string select) {
return getObjects(objectType, select, -1);
}
///
/// Get objects matching the select, limiting the maximum result set
///
public ArrayList getObjects(Type objectType, string select, int maximumResultsLimit) {
return getObjects(objectType, select, null,0,maximumResultsLimit);
}
///
/// Get objects matching the select, limiting the maximum result set
///
public ArrayList getObjects(Type objectType, string select, string orderByStatement, int startIndex, int limit) {
WmIntermediateObject intermediateObject = getIntermediateObject(objectType, true);
ArrayList resultList = new ArrayList();
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
string cmdText = "SELECT * FROM " + dataBaseCredentials.Catalog + "." + intermediateObject.TableName;
if (!String.IsNullOrEmpty(select)) {
cmdText += " WHERE " + select;
}
if(!String.IsNullOrEmpty(orderByStatement)){
cmdText+= " "+orderByStatement+" ";
}
string limitStatement = null;
if (startIndex > 0 && limit < 0) {
limitStatement = "LIMIT " + startIndex + ",10000000000000000000";
} else if (startIndex > 0 && limit > 0) {
limitStatement = "LIMIT " + startIndex + "," + limit;
} else if (limit > 0) {
limitStatement = "LIMIT " + limit;
}
cmdText += " "+limitStatement;
MySqlCommand command = new MySqlCommand(cmdText, connection);
try {
connection.Open();
MySqlDataReader reader = command.ExecuteReader();
while (reader.Read()) {
object objectInstance = intermediateObject.Creator.Invoke();
foreach (WmIntermediateObjectProperty property in intermediateObject.Properties) {
int ordinal = property.DataColumnIndex;
if (ordinal == -1) {
ordinal = reader.GetOrdinal(property.DataName);
property.DataColumnIndex = ordinal;
}
object value = reader[ordinal];
if (value != null && !(value is DBNull)) {
if (value is sbyte) {
value = Convert.ToBoolean(value);
}
property.Setter.Invoke(objectInstance, value);
}
}
resultList.Add(objectInstance);
}
reader.Close();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in getObjects. " + error.Message);
} finally {
connection.Close();
}
return resultList;
}
///
/// Returns the current row count using a SQL COUNT statement
///
public override int getRowCount(Type objectType) {
string cmdText = "SELECT COUNT(*) FROM " + dataBaseCredentials.Catalog + "." + WmDataTools.getTableName(objectType) + ";";
object returnValue = getObjectFromSQL(cmdText);
if (!(returnValue is long)) {
return 0;
} else {
return Convert.ToInt32((long)returnValue);
}
}
#endregion
///
/// Returns an ArrayList of objects resulting from a full query, converted into the target objec type. Try to talk one query per object target type and for maximum performance (resultSetColumnsAreAlwaysInTheSameOrder=true)
///
public ArrayList getObjectsFromFullQuery(string fullQuery, Type targetObjectType, bool resultSetColumnsAreAlwaysInTheSameOrder) {
WmIntermediateObject intermediateObject = getIntermediateObject(targetObjectType,false);
ArrayList resultList = new ArrayList();
MySqlConnection connection = new MySqlConnection(dataBaseCredentials.getConnectionString());
string cmdText = fullQuery;
MySqlCommand command = new MySqlCommand(cmdText, connection);
try {
connection.Open();
MySqlDataReader reader = command.ExecuteReader();
while (reader.Read()) {
object objectInstance = intermediateObject.Creator.Invoke();
foreach (WmIntermediateObjectProperty property in intermediateObject.Properties) {
int ordinal = property.DataColumnIndex;
object value = null;
if (resultSetColumnsAreAlwaysInTheSameOrder) { // then we use the fast way of reading columns
if (ordinal == -1) {
ordinal = reader.GetOrdinal(property.DataName);
property.DataColumnIndex = ordinal;
}
if(ordinal!=-1){ // we don't know if the resultset contains every property of the target object, ignore any missing
value = reader[ordinal];
}
} else { // this is the slower method, reading values by property data names
value = reader[property.DataName];
}
if (value != null && !(value is DBNull)) {
if (value is sbyte) {
value = Convert.ToBoolean(value);
}
property.Setter.Invoke(objectInstance, value);
}
}
resultList.Add(objectInstance);
}
reader.Close();
} catch (Exception error) {
throw new Exception("WmDirectData: Exception occured in getObjectsFromFullQuery. " + error.Message);
} finally {
connection.Close();
}
return resultList;
}
}
}