/// <summary> /// Retrieve a Collection of DataObjects Sets from database filtered by Parametrized Where Expression /// </summary> /// <param name="tableHandler">Table Handler for these DataObjects</param> /// <param name="whereExpression">Parametrized Where Expression</param> /// <param name="parameters">Parameters for filtering</param> /// <param name="isolation">Isolation Level</param> /// <returns>Collection of DataObjects Sets matching Parametrized Where Expression</returns> protected override IList <IList <DataObject> > SelectObjectsImpl(DataTableHandler tableHandler, string whereExpression, IEnumerable <IEnumerable <QueryParameter> > parameters, Transaction.IsolationLevel isolation) { var columns = tableHandler.FieldElementBindings.ToArray(); string command = null; if (!string.IsNullOrEmpty(whereExpression)) { command = string.Format("SELECT {0} FROM `{1}` WHERE {2}", string.Join(", ", columns.Select(col => string.Format("`{0}`", col.ColumnName))), tableHandler.TableName, whereExpression); } else { command = string.Format("SELECT {0} FROM `{1}`", string.Join(", ", columns.Select(col => string.Format("`{0}`", col.ColumnName))), tableHandler.TableName); } var primary = columns.FirstOrDefault(col => col.PrimaryKey != null); var dataObjects = new List <IList <DataObject> >(); ExecuteSelectImpl(command, parameters, reader => FillQueryResultList(reader, tableHandler, columns, primary, dataObjects)); return(dataObjects.ToArray()); }
public void TestAllAvailableTables() { foreach (Assembly assembly in new [] { typeof(GameServer).Assembly, typeof(DataObject).Assembly }) { // Walk through each type in the assembly foreach (Type type in assembly.GetTypes()) { if (!type.IsClass || type.IsAbstract) continue; var attrib = type.GetCustomAttributes<DataTable>(false); if (attrib.Any()) { Assert.DoesNotThrow( () => { var dth = new DataTableHandler(type); Database.CheckOrCreateTableImpl(dth); }, "Registering All Projects Tables should not throw Exceptions... (Failed on Type {0})", type.FullName); Database.RegisterDataObject(type); var selectall = typeof(IObjectDatabase).GetMethod("SelectAllObjects", new Type[] { }).MakeGenericMethod(type); object objs = null; Assert.DoesNotThrow( () => { objs = selectall.Invoke(Database, new object[] { }); }, "Registered tables should not Throw Exception on Select All... (Failed on Type {0})", type); Assert.IsNotNull(objs); } } } }
/// <summary> /// Register Data Object Type if not already Registered /// </summary> /// <param name="dataObjectType">DataObject Type</param> public override void RegisterDataObject(Type dataObjectType) { var tableName = AttributesUtils.GetTableOrViewName(dataObjectType); var isView = AttributesUtils.GetViewName(dataObjectType) != null; var viewAs = AttributesUtils.GetViewAs(dataObjectType); DataTableHandler existingHandler; if (TableDatasets.TryGetValue(tableName, out existingHandler)) { if (dataObjectType != existingHandler.ObjectType) { throw new DatabaseException(string.Format("Table Handler Duplicate for Type: {2}, Table Name '{0}' Already Registered with Type : {1}", tableName, existingHandler.ObjectType, dataObjectType)); } return; } var dataTableHandler = new DataTableHandler(dataObjectType); try { if (isView) { if (!string.IsNullOrEmpty(viewAs)) { ExecuteNonQueryImpl(string.Format("DROP VIEW IF EXISTS `{0}`", tableName)); ExecuteNonQueryImpl(string.Format("CREATE VIEW `{0}` AS {1}", tableName, string.Format(viewAs, string.Format("`{0}`", AttributesUtils.GetTableName(dataObjectType))))); } } else { CheckOrCreateTableImpl(dataTableHandler); } lock (Lock) { TableDatasets.Add(tableName, dataTableHandler); } // Init PreCache if (dataTableHandler.UsesPreCaching) { var primary = dataTableHandler.PrimaryKeys.Single(); var objects = MultipleSelectObjectsImpl(dataTableHandler, new [] { WhereClause.Empty }).First(); foreach (var obj in objects) { dataTableHandler.SetPreCachedObject(primary.GetValue(obj), obj); } } } catch (Exception e) { if (log.IsErrorEnabled) { log.ErrorFormat("RegisterDataObject: Error While Registering Table \"{0}\"\n{1}", tableName, e); } } }
private void FillQueryResultList(IDataReader reader, DataTableHandler tableHandler, ElementBinding[] columns, ElementBinding primary, List <IList <DataObject> > resultList) { var list = new List <DataObject>(); var data = new object[reader.FieldCount]; while (reader.Read()) { reader.GetValues(data); var obj = Activator.CreateInstance(tableHandler.ObjectType) as DataObject; // Fill Object var current = 0; foreach (var column in columns) { DatabaseSetValue(obj, column, data[current]); current++; } // Set Primary Key if (primary != null) { obj.ObjectId = primary.GetValue(obj).ToString(); } list.Add(obj); obj.Dirty = false; obj.IsPersisted = true; } resultList.Add(list.ToArray()); }
/// <summary> /// Retrieve a Collection of DataObjects from database based on their primary key values /// </summary> /// <param name="tableHandler">Table Handler for the DataObjects to Retrieve</param> /// <param name="keys">Collection of Primary Key Values</param> /// <returns>Collection of DataObject with primary key matching values</returns> protected override IEnumerable <DataObject> FindObjectByKeyImpl(DataTableHandler tableHandler, IEnumerable <object> keys) { // Primary Key var primary = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey != null) .Select(bind => new { ColumnName = string.Format("`{0}`", bind.ColumnName), ParamName = string.Format("@{0}", bind.ColumnName), ParamType = bind.ValueType }).ToArray(); if (!primary.Any()) { throw new DatabaseException(string.Format("Table {0} has no primary key for finding by key...", tableHandler.TableName)); } var whereClauses = new List <WhereClause>(); foreach (var key in keys) { var whereClause = WhereClause.Empty; foreach (var column in primary) { whereClause = whereClause.And(DB.Column(column.ColumnName).IsEqualTo(key)); } whereClauses.Add(whereClause); } var resultByKeys = MultipleSelectObjectsImpl(tableHandler, whereClauses).Select(results => results.SingleOrDefault()); return(resultByKeys.ToArray()); }
public void TestWrongDataObject() { Assert.Throws(typeof(ArgumentException), () => { var dth = new DataTableHandler(typeof(AttributesUtils)); Database.CheckOrCreateTableImpl(dth); }, "Registering a wrong DataObject should throw Argument Exception"); }
/// <summary> /// Deletes DataObjects from the database. /// </summary> /// <param name="dataObjects">DataObjects to delete from the database</param> /// <param name="tableHandler">Table Handler for the DataObjects Collection</param> /// <returns>True if objects were deleted successfully; false otherwise</returns> protected override IEnumerable <bool> DeleteObjectImpl(DataTableHandler tableHandler, IEnumerable <DataObject> dataObjects) { var success = new List <bool>(); if (!dataObjects.Any()) { return(success); } try { // Get Primary Keys var primary = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey != null).ToArray(); if (!primary.Any()) { throw new DatabaseException(string.Format("Table {0} has no primary key for deletion...", tableHandler.TableName)); } var command = string.Format("DELETE FROM `{0}` WHERE {1}", tableHandler.TableName, string.Join(" AND ", primary.Select(col => string.Format("`{0}` = @{0}", col.ColumnName)))); var objs = dataObjects.ToArray(); var parameters = objs.Select(obj => primary.Select(pk => new QueryParameter(string.Format("@{0}", pk.ColumnName), pk.GetValue(obj), pk.ValueType))); var affected = ExecuteNonQueryImpl(command, parameters); var resultByObjects = affected.Select((result, index) => new { Result = result, DataObject = objs[index] }); foreach (var result in resultByObjects) { if (result.Result > 0) { result.DataObject.IsPersisted = false; result.DataObject.IsDeleted = true; success.Add(true); } else { if (Log.IsErrorEnabled) { Log.ErrorFormat("Error deleting data object from table {0} Object = {1} --- keyvalue changed? {2}\n{3}", tableHandler.TableName, result.DataObject, command, Environment.StackTrace); } success.Add(false); } } } catch (Exception e) { if (Log.IsErrorEnabled) { Log.ErrorFormat("Error while deleting data object in table: {0}\n{1}", tableHandler.TableName, e); } } return(success); }
/// <summary> /// Retrieve a Collection of DataObjects Sets from database filtered by Parametrized Where Expression /// </summary> /// <param name="tableHandler">Table Handler for these DataObjects</param> /// <param name="whereExpression">Parametrized Where Expression</param> /// <param name="parameters">Parameters for filtering</param> /// <param name="isolation">Isolation Level</param> /// <returns>Collection of DataObjects Sets matching Parametrized Where Expression</returns> protected override IList <IList <DataObject> > SelectObjectsImpl(DataTableHandler tableHandler, string whereExpression, IEnumerable <IEnumerable <QueryParameter> > parameters, Transaction.IsolationLevel isolation) { var columns = tableHandler.FieldElementBindings.ToArray(); string command = null; if (!string.IsNullOrEmpty(whereExpression)) { command = string.Format( "SELECT {0} FROM `{1}` WHERE {2}", string.Join(", ", columns.Select(col => string.Format("`{0}`", col.ColumnName))), tableHandler.TableName, whereExpression); } else { command = string.Format( "SELECT {0} FROM `{1}`", string.Join(", ", columns.Select(col => string.Format("`{0}`", col.ColumnName))), tableHandler.TableName); } var primary = columns.FirstOrDefault(col => col.PrimaryKey != null); var dataObjects = new List <IList <DataObject> >(); ExecuteSelectImpl(command, parameters, reader => { var list = new List <DataObject>(); var data = new object[reader.FieldCount]; while (reader.Read()) { reader.GetValues(data); var obj = Activator.CreateInstance(tableHandler.ObjectType) as DataObject; // Fill Object var current = 0; foreach (var column in columns) { DatabaseSetValue(obj, column, data[current]); current++; } // Set Primary Key if (primary != null) { obj.ObjectId = primary.GetValue(obj).ToString(); } list.Add(obj); obj.Dirty = false; obj.IsPersisted = true; } dataObjects.Add(list.ToArray()); }, isolation); return(dataObjects.ToArray()); }
protected void ReloadCache(string tableName) { DataTableHandler handler = TableDatasets[tableName]; ICache cache = handler.Cache; foreach (object o in cache.Keys) { ReloadObject(cache[o] as DataObject); } }
/// <summary> /// Register Data Object Type if not already Registered /// </summary> /// <param name="dataObjectType">DataObject Type</param> public virtual void RegisterDataObject(Type dataObjectType) { var tableName = AttributesUtils.GetTableOrViewName(dataObjectType); if (TableDatasets.ContainsKey(tableName)) { return; } var dataTableHandler = new DataTableHandler(dataObjectType); TableDatasets.Add(tableName, dataTableHandler); }
protected override IList <IList <DataObject> > MultipleSelectObjectsImpl(DataTableHandler tableHandler, IEnumerable <WhereClause> whereClauseBatch) { var columns = tableHandler.FieldElementBindings.ToArray(); string selectFromExpression = string.Format("SELECT {0} FROM `{1}` ", string.Join(", ", columns.Select(col => string.Format("`{0}`", col.ColumnName))), tableHandler.TableName); var primary = columns.FirstOrDefault(col => col.PrimaryKey != null); var dataObjects = new List <IList <DataObject> >(); ExecuteSelectImpl(selectFromExpression, whereClauseBatch, reader => FillQueryResultList(reader, tableHandler, columns, primary, dataObjects)); return(dataObjects.ToArray()); }
/// <summary> /// List all Unique Members of a DataTable, Using them for duplicate Matching. /// </summary> /// <param name="objectType">DataObject Type</param> /// <returns>List of MemberInfo having Unique Attributes</returns> public static ElementBinding[][] GetUniqueMembers(Type objectType) { var tableHandler = new DataTableHandler(objectType); var uniques = tableHandler.Table.Constraints.OfType <UniqueConstraint>().Where(constraint => !constraint.IsPrimaryKey) .Select(constraint => constraint.Columns .Select(col => tableHandler.FieldElementBindings.Single(bind => bind.ColumnName.Equals(col.ColumnName, StringComparison.OrdinalIgnoreCase))) .ToArray()); var primary = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey != null && !bind.PrimaryKey.AutoIncrement && !bind.ColumnName.Equals(tableHandler.PrimaryKeyColumnName, StringComparison.OrdinalIgnoreCase)) .ToArray(); return(new [] { primary }.Concat(uniques).ToArray()); }
/// <summary> /// List all Unique Members of a DataTable, Using them for duplicate Matching. /// </summary> /// <param name="objectType">DataObject Type</param> /// <returns>List of MemberInfo having Unique Attributes</returns> public static ElementBinding[][] GetUniqueMembers(Type objectType) { var tableHandler = new DataTableHandler(objectType); var uniques = tableHandler.Table.Constraints.OfType<UniqueConstraint>().Where(constraint => !constraint.IsPrimaryKey) .Select(constraint => constraint.Columns .Select(col => tableHandler.FieldElementBindings.Single(bind => bind.ColumnName.Equals(col.ColumnName, StringComparison.OrdinalIgnoreCase))) .ToArray()); var primary = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey != null && !bind.PrimaryKey.AutoIncrement && !bind.ColumnName.Equals(string.Format("{0}_ID", tableHandler.TableName), StringComparison.OrdinalIgnoreCase)) .ToArray(); return new [] { primary }.Concat(uniques).ToArray(); }
/// <summary> /// Selects object from the db and updates or adds entry in the pre-cache /// </summary> /// <param name="objectType"></param> /// <param name="key"></param> public bool UpdateInCache <TObject>(object key) where TObject : DataObject { MemberInfo[] members = typeof(TObject).GetMembers(); var ret = (TObject)Activator.CreateInstance(typeof(TObject)); string tableName = ret.TableName; DataTableHandler dth = TableDatasets[tableName]; string whereClause = null; if (!dth.UsesPreCaching || key == null) { return(false); } // Escape PK value key = Escape(key.ToString()); for (int i = 0; i < members.Length; i++) { object[] keyAttrib = members[i].GetCustomAttributes(typeof(PrimaryKey), true); if (keyAttrib.Length > 0) { whereClause = "`" + members[i].Name + "` = '" + key + "'"; break; } } if (whereClause == null) { whereClause = "`" + ret.TableName + "_ID` = '" + key + "'"; } var objs = SelectObjects <TObject>(whereClause); if (objs.Count > 0) { dth.SetPreCachedObject(key, objs[0]); return(true); } return(false); }
/// <summary> /// List Remarkable Members of a DataTable, Using them for Default Ordering /// This includes non-generated Primary Key, Unique Field, and Indexed Fields (optionnaly) /// </summary> /// <param name="objectType">DataObject Type</param> /// <param name="forceIndexes">Returns Indexes even if enough Unique type have been gathered</param> /// <returns>List of Remkarkable MemberInfo of given DataObject</returns> public static ElementBinding[] GetRemarkableMembers(Type objectType, bool forceIndexes) { var tableHandler = new DataTableHandler(objectType); // Find unique Fields var remarkableMember = GetUniqueMembers(objectType); // We don't have enough fields, Try indexes ! if (remarkableMember.Length < 1 || forceIndexes) { var indexes = tableHandler.Table.ExtendedProperties["INDEXES"] as Dictionary <string, DataColumn[]>; return(remarkableMember.SelectMany(constraint => constraint) .Concat(indexes.SelectMany(index => index.Value).Select(col => tableHandler.FieldElementBindings .Single(bind => bind.ColumnName.Equals(col.ColumnName, StringComparison.OrdinalIgnoreCase)))) .ToArray()); } return(remarkableMember.SelectMany(constraint => constraint).ToArray()); }
/// <summary> /// List Remarkable Members of a DataTable, Using them for Default Ordering /// This includes non-generated Primary Key, Unique Field, and Indexed Fields (optionnaly) /// </summary> /// <param name="objectType">DataObject Type</param> /// <param name="forceIndexes">Returns Indexes even if enough Unique type have been gathered</param> /// <returns>List of Remkarkable MemberInfo of given DataObject</returns> public static ElementBinding[] GetRemarkableMembers(Type objectType, bool forceIndexes) { var tableHandler = new DataTableHandler(objectType); // Find unique Fields var remarkableMember = GetUniqueMembers(objectType); // We don't have enough fields, Try indexes ! if (remarkableMember.Length < 1 || forceIndexes) { var indexes = tableHandler.Table.ExtendedProperties["INDEXES"] as Dictionary<string, DataColumn[]>; return remarkableMember.SelectMany(constraint => constraint) .Concat(indexes.SelectMany(index => index.Value).Select(col => tableHandler.FieldElementBindings .Single(bind => bind.ColumnName.Equals(col.ColumnName, StringComparison.OrdinalIgnoreCase)))) .ToArray(); } return remarkableMember.SelectMany(constraint => constraint).ToArray(); }
/// <summary> /// Retrieve a Collection of DataObjects from database based on their primary key values /// </summary> /// <param name="tableHandler">Table Handler for the DataObjects to Retrieve</param> /// <param name="keys">Collection of Primary Key Values</param> /// <returns>Collection of DataObject with primary key matching values</returns> protected override IEnumerable <DataObject> FindObjectByKeyImpl(DataTableHandler tableHandler, IEnumerable <object> keys) { // Primary Key var primary = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey != null) .Select(bind => new { ColumnName = string.Format("`{0}`", bind.ColumnName), ParamName = string.Format("@{0}", bind.ColumnName) }).ToArray(); if (!primary.Any()) { throw new DatabaseException(string.Format("Table {0} has no primary key for finding by key...", tableHandler.TableName)); } var whereClause = string.Format("{0}", string.Join(" AND ", primary.Select(col => string.Format("{0} = {1}", col.ColumnName, col.ParamName)))); var keysArray = keys.ToArray(); var parameters = keysArray.Select(key => primary.Select(col => new QueryParameter(col.ParamName, key))); var objs = SelectObjectsImpl(tableHandler, whereClause, parameters, Transaction.IsolationLevel.DEFAULT); var resultByKeys = objs.Select((results, index) => new { Key = keysArray[index], DataObject = results.SingleOrDefault() }); return(resultByKeys.Select(obj => obj.DataObject).ToArray()); }
protected void DeleteFromCache(string tableName, DataObject obj) { DataTableHandler handler = TableDatasets[tableName]; handler.SetCacheObject(obj.ObjectId, null); }
public void RegisterDataObject(Type objType) { if (TableDatasets.ContainsKey(GetTableOrViewName(objType))) { return; } bool primaryKeySpecified = false; bool useAutoIncrementColumn = false; bool relations = false; MemberInfo primaryIndexMember = null; string tableName = GetTableOrViewName(objType); var ds = new DataSet(); var table = new DataTable(tableName); MemberInfo[] myMembers = objType.GetMembers(); for (int i = 0; i < myMembers.Length; i++) { //object[] myAttributes = myMembers[i].GetCustomAttributes(true); //object[] myAttributes = myMembers[i].GetCustomAttributes(typeof(DOL.Database.Attributes.DataElement), true); object[] myAttributes = myMembers[i].GetCustomAttributes(typeof(PrimaryKey), true); if (myAttributes.Length > 0) { primaryKeySpecified = true; if (myMembers[i] is PropertyInfo) { table.Columns.Add(myMembers[i].Name, ((PropertyInfo)myMembers[i]).PropertyType); } else { table.Columns.Add(myMembers[i].Name, ((FieldInfo)myMembers[i]).FieldType); } table.Columns[myMembers[i].Name].AutoIncrement = ((PrimaryKey)myAttributes[0]).AutoIncrement; useAutoIncrementColumn = table.Columns[myMembers[i].Name].AutoIncrement; var index = new DataColumn[1]; index[0] = table.Columns[myMembers[i].Name]; primaryIndexMember = myMembers[i]; table.PrimaryKey = index; continue; } myAttributes = myMembers[i].GetCustomAttributes(typeof(DataElement), true); if (myAttributes.Length > 0) { //if(myAttributes[0] is Attributes.DataElement) //{ if (myMembers[i] is PropertyInfo) { table.Columns.Add(myMembers[i].Name, ((PropertyInfo)myMembers[i]).PropertyType); } else { table.Columns.Add(myMembers[i].Name, ((FieldInfo)myMembers[i]).FieldType); } table.Columns[myMembers[i].Name].AllowDBNull = ((DataElement)myAttributes[0]).AllowDbNull; if (((DataElement)myAttributes[0]).Unique) { table.Constraints.Add(new UniqueConstraint("UNIQUE_" + myMembers[i].Name, table.Columns[myMembers[i].Name])); } if (((DataElement)myAttributes[0]).IndexColumns != string.Empty) { table.Columns[myMembers[i].Name].ExtendedProperties.Add("INDEX", true); table.Columns[myMembers[i].Name].ExtendedProperties.Add("INDEXCOLUMNS", ((DataElement)myAttributes[0]).IndexColumns); } else if (((DataElement)myAttributes[0]).Index) { table.Columns[myMembers[i].Name].ExtendedProperties.Add("INDEX", true); } if (((DataElement)myAttributes[0]).Varchar > 0) { table.Columns[myMembers[i].Name].ExtendedProperties.Add("VARCHAR", ((DataElement)myAttributes[0]).Varchar); } //if(myAttributes[0] is Attributes.PrimaryKey) myAttributes = GetRelationAttributes(myMembers[i]); //if(myAttributes[0] is Attributes.Relation) if (myAttributes.Length > 0) { relations = true; } } } if (useAutoIncrementColumn == false) { // We define the Tablename_ID column that will always contain a generated unique ID DataColumn idColumn = table.Columns.Add(tableName + "_ID", typeof(string)); if (primaryKeySpecified) { // if another primary key is defined on this table but the TableName_ID column is still being used then force // the creation of a unique index on the the TableName_ID column table.Constraints.Add(new UniqueConstraint(idColumn.ColumnName, idColumn)); } } if (primaryKeySpecified == false) { var index = new DataColumn[1]; index[0] = table.Columns[tableName + "_ID"]; table.PrimaryKey = index; } if (Connection.IsSQLConnection) { Connection.CheckOrCreateTable(table); } ds.DataSetName = tableName; ds.EnforceConstraints = true; ds.CaseSensitive = false; ds.Tables.Add(table); var dth = new DataTableHandler(ds); dth.HasRelations = relations; dth.UsesPreCaching = DataObject.GetPreCachedFlag(objType); TableDatasets.Add(tableName, dth); //if (dth.UsesPreCaching && Connection.IsSQLConnection) //{ // // not useful for xml connection // if (Log.IsDebugEnabled) // Log.Debug("Precaching of " + table.TableName + "..."); // var objects = SQLSelectObjects<TObject>(""); // object key; // for (int i = 0; i < objects.Length; i++) // { // key = null; // if (primaryIndexMember == null) // { // key = objects[i].ObjectId; // } // else // { // if (primaryIndexMember is PropertyInfo) // { // key = ((PropertyInfo) primaryIndexMember).GetValue(objects[i], null); // } // else if (primaryIndexMember is FieldInfo) // { // key = ((FieldInfo) primaryIndexMember).GetValue(objects[i]); // } // } // if (key != null) // { // dth.SetPreCachedObject(key, objects[i]); // } // else // { // if (Log.IsErrorEnabled) // Log.Error("Primary key is null! " + ((primaryIndexMember != null) ? primaryIndexMember.Name : "")); // } // } // if (Log.IsDebugEnabled) // Log.Debug("Precaching of " + table.TableName + " finished!"); //} }
/// <summary> /// Deletes DataObjects from the database. /// </summary> /// <param name="dataObjects">DataObjects to delete from the database</param> /// <param name="tableHandler">Table Handler for the DataObjects Collection</param> /// <returns>True if objects were deleted successfully; false otherwise</returns> protected abstract IEnumerable <bool> DeleteObjectImpl(DataTableHandler tableHandler, IEnumerable <DataObject> dataObjects);
/// <summary> /// Retrieve a Collection of DataObjects Sets from database filtered by Parametrized Where Expression /// </summary> /// <param name="tableHandler">Table Handler for these DataObjects</param> /// <param name="whereExpression">Parametrized Where Expression</param> /// <param name="parameters">Parameters for filtering</param> /// <param name="isolation">Isolation Level</param> /// <returns>Collection of DataObjects Sets matching Parametrized Where Expression</returns> protected abstract IList <IList <DataObject> > SelectObjectsImpl(DataTableHandler tableHandler, string whereExpression, IEnumerable <IEnumerable <QueryParameter> > parameters, Transaction.IsolationLevel isolation);
protected abstract IList <IList <DataObject> > MultipleSelectObjectsImpl(DataTableHandler tableHandler, IEnumerable <WhereClause> whereClauseBatch);
/// <summary> /// Delete Relations Objects attached to DataObjects /// </summary> /// <param name="tableHandler">TableHandler for Source DataObjects Relation</param> /// <param name="dataObjects">DataObjects to parse</param> /// <returns>True if all Relations were deleted</returns> public bool DeleteObjectRelations(DataTableHandler tableHandler, IEnumerable <DataObject> dataObjects) { var success = true; foreach (var relation in tableHandler.ElementBindings.Where(bind => bind.Relation != null && bind.Relation.AutoDelete)) { // Relation Check var remoteHandler = GetTableHandler(relation.ValueType); if (remoteHandler == null) { if (log.IsErrorEnabled) { log.ErrorFormat("DeleteObjectRelations: Remote Table for Type ({0}) is not registered !", relation.ValueType.FullName); } success = false; continue; } // Check For Array Type var groups = relation.ValueType.HasElementType ? dataObjects.Select(obj => new { Source = obj, Enumerable = (IEnumerable <DataObject>)relation.GetValue(obj) }) .Where(obj => obj.Enumerable != null).Select(obj => obj.Enumerable.Select(rel => new { Local = obj.Source, Remote = rel })) .SelectMany(obj => obj).Where(obj => obj.Remote != null && obj.Remote.IsPersisted) : dataObjects.Select(obj => new { Local = obj, Remote = (DataObject)relation.GetValue(obj) }).Where(obj => obj.Remote != null && obj.Remote.IsPersisted); foreach (var grp in groups.GroupBy(obj => obj.Remote.AllowDelete)) { if (grp.Key) { var objs = grp.ToArray(); var results = DeleteObjectImpl(remoteHandler, objs.Select(obj => obj.Remote)); var resultsByObjs = results.Select((result, index) => new { Success = result, RelObject = objs[index] }); foreach (var resultGrp in resultsByObjs.GroupBy(obj => obj.Success)) { if (resultGrp.Key) { // Delete in Precache if tablehandler use it if (remoteHandler.UsesPreCaching) { var primary = remoteHandler.PrimaryKey; if (primary != null) { foreach (var successObj in resultGrp.Select(obj => obj.RelObject.Remote)) { remoteHandler.DeletePreCachedObject(primary.GetValue(successObj)); } } } } else { foreach (var result in resultGrp) { if (log.IsErrorEnabled) { log.ErrorFormat("DeleteObjectRelations: Deleting Relation ({0}) of DataObject ({1}) failed for Object ({2})", relation.ValueType, result.RelObject.Local, result.RelObject.Remote); } } success = false; } } } else { // Objects that could not be deleted can lead to failure if (log.IsWarnEnabled) { foreach (var obj in grp) { log.WarnFormat("DeleteObjectRelations: DataObject ({0}) not allowed to be deleted from Database", obj); } } success = false; } } } return(success); }
/// <summary> /// Populate or Refresh Object Relation Implementation /// </summary> /// <param name="relationBind">Element Binding for Relation Field</param> /// <param name="localBind">Local Binding for Value Match</param> /// <param name="remoteBind">Remote Binding for Column Match</param> /// <param name="remoteHandler">Remote Table Handler for Cache Retrieving</param> /// <param name="dataObjects">DataObjects to Populate</param> protected virtual void FillObjectRelationsImpl(ElementBinding relationBind, ElementBinding localBind, ElementBinding remoteBind, DataTableHandler remoteHandler, IEnumerable <DataObject> dataObjects) { var type = relationBind.ValueType; var isElementType = false; if (type.HasElementType) { type = type.GetElementType(); isElementType = true; } var objects = dataObjects.ToArray(); IEnumerable <IEnumerable <DataObject> > objsResults = null; // Handle Cache Search if relevent or use a Select Query if (remoteHandler.UsesPreCaching) { // Search with Primary Key or use a Where Clause if (remoteHandler.PrimaryKeys.All(pk => pk.ColumnName.Equals(remoteBind.ColumnName, StringComparison.OrdinalIgnoreCase))) { objsResults = objects.Select(obj => { var local = localBind.GetValue(obj); if (local == null) { return(new DataObject[0]); } var retrieve = remoteHandler.GetPreCachedObject(local); if (retrieve == null) { return(new DataObject[0]); } return(new [] { retrieve }); }); } else { objsResults = objects .Select(obj => remoteHandler.SearchPreCachedObjects(rem => { var local = localBind.GetValue(obj); var remote = remoteBind.GetValue(rem); if (local == null || remote == null) { return(false); } if (localBind.ValueType == typeof(string) || remoteBind.ValueType == typeof(string)) { return(remote.ToString().Equals(local.ToString(), StringComparison.OrdinalIgnoreCase)); } return(remote == local); })); } } else { var whereClauses = objects.Select(obj => DB.Column(remoteBind.ColumnName).IsEqualTo(localBind.GetValue(obj))); objsResults = MultipleSelectObjectsImpl(remoteHandler, whereClauses); } var resultByObjs = objsResults.Select((obj, index) => new { DataObject = objects[index], Results = obj }).ToArray(); // Store Relations foreach (var result in resultByObjs) { if (isElementType) { if (result.Results.Any()) { MethodInfo castMethod = typeof(Enumerable).GetMethod("OfType").MakeGenericMethod(type); MethodInfo methodToArray = typeof(Enumerable).GetMethod("ToArray").MakeGenericMethod(type); relationBind.SetValue(result.DataObject, methodToArray.Invoke(null, new object[] { castMethod.Invoke(null, new object[] { result.Results }) })); } else { relationBind.SetValue(result.DataObject, null); } } else { relationBind.SetValue(result.DataObject, result.Results.SingleOrDefault()); } } // Fill Sub Relations FillObjectRelations(resultByObjs.SelectMany(result => result.Results), false); }
/// <summary> /// Adds new DataObjects to the database. /// </summary> /// <param name="dataObjects">DataObjects to add to the database</param> /// <param name="tableHandler">Table Handler for the DataObjects Collection</param> /// <returns>True if objects were added successfully; false otherwise</returns> protected override IEnumerable <bool> AddObjectImpl(DataTableHandler tableHandler, IEnumerable <DataObject> dataObjects) { var success = new List <bool>(); if (!dataObjects.Any()) { return(success); } try { // Check Primary Keys var usePrimaryAutoInc = tableHandler.FieldElementBindings.Any(bind => bind.PrimaryKey != null && bind.PrimaryKey.AutoIncrement); // Columns var columns = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey == null || !bind.PrimaryKey.AutoIncrement) .Select(bind => new { Binding = bind, ColumnName = string.Format("`{0}`", bind.ColumnName), ParamName = string.Format("@{0}", bind.ColumnName) }).ToArray(); // Prepare SQL Query var command = string.Format("INSERT INTO `{0}` ({1}) VALUES({2})", tableHandler.TableName, string.Join(", ", columns.Select(col => col.ColumnName)), string.Join(", ", columns.Select(col => col.ParamName))); var objs = dataObjects.ToArray(); // Init Object Id GUID foreach (var obj in objs.Where(obj => obj.ObjectId == null)) { obj.ObjectId = IDGenerator.GenerateID(); } // Build Parameters var parameters = objs.Select(obj => columns.Select(col => new QueryParameter(col.ParamName, col.Binding.GetValue(obj)))); // Primary Key Auto Inc Handler if (usePrimaryAutoInc) { var lastId = ExecuteScalarImpl(command, parameters, true); var binding = tableHandler.FieldElementBindings.First(bind => bind.PrimaryKey != null && bind.PrimaryKey.AutoIncrement); var resultByObjects = lastId.Select((result, index) => new { Result = Convert.ToInt64(result), DataObject = objs[index] }); foreach (var result in resultByObjects) { if (result.Result > 0) { DatabaseSetValue(result.DataObject, binding, result.Result); result.DataObject.ObjectId = result.Result.ToString(); result.DataObject.Dirty = false; result.DataObject.IsPersisted = true; result.DataObject.IsDeleted = false; success.Add(true); } else { if (Log.IsErrorEnabled) { Log.ErrorFormat("Error adding data object into {0} Object = {1}, UsePrimaryAutoInc, Query = {2}", tableHandler.TableName, result.DataObject, command); } success.Add(false); } } } else { var affected = ExecuteNonQueryImpl(command, parameters); var resultByObjects = affected.Select((result, index) => new { Result = result, DataObject = objs[index] }); foreach (var result in resultByObjects) { if (result.Result > 0) { result.DataObject.Dirty = false; result.DataObject.IsPersisted = true; result.DataObject.IsDeleted = false; success.Add(true); } else { if (Log.IsErrorEnabled) { Log.ErrorFormat("Error adding data object into {0} Object = {1} Query = {2}", tableHandler.TableName, result.DataObject, command); } success.Add(false); } } } } catch (Exception e) { if (Log.IsErrorEnabled) { Log.ErrorFormat("Error while adding data objects in table: {0}\n{1}", tableHandler.TableName, e); } } return(success); }
/// <summary> /// Check the XML Package Given for Replace or Insert Apply /// </summary> /// <param name="xml">FileInfo for XML Package</param> /// <param name="replace">Enforce Replace Mode</param> /// <returns>True if success, False if any errors</returns> private bool CheckXMLPackageAndApply(FileInfo xml, bool replace) { var packageName = string.Format("{0}{1}{2}", xml.Directory.Name, Path.DirectorySeparatorChar, xml.Name); if (log.IsInfoEnabled) log.InfoFormat("Auto Loading XML File {0} into Database (Mode:{1})", packageName, replace ? "Replace" : "Insert"); var result = true; try { //Load the XML File var xmlTable = LoaderUnloaderXML.LoadXMLTableFromFile(xml); if (xmlTable.Length > 0) { // Guess Object Type var xmlType = xmlTable.First().GetType(); var tableHandler = new DataTableHandler(xmlType); // Find unique Fields var uniqueMember = DatabaseUtils.GetUniqueMembers(xmlType); // Get all object "Method" Through Reflection var classMethod = GameServer.Database.GetType().GetMethod("SelectAllObjects", Type.EmptyTypes); var genericMethod = classMethod.MakeGenericMethod(xmlType); var existingObjects = ((IEnumerable)genericMethod.Invoke(GameServer.Database, new object[]{})).Cast<DataObject>().ToArray(); // Store Object to Alter var toDelete = new ConcurrentBag<DataObject>(); var toAdd = new ConcurrentBag<DataObject>(); // Check if an Object already exists xmlTable.AsParallel().ForAll(obj => { // Check if Exists Compare Unique and Non-Generated Primary Keys var exists = existingObjects .FirstOrDefault(entry => uniqueMember .Any(constraint => constraint .All(bind => bind.ValueType == typeof(string) ? bind.GetValue(entry).ToString().Equals(bind.GetValue(obj).ToString(), StringComparison.OrdinalIgnoreCase) : bind.GetValue(entry) == bind.GetValue(obj))) ); if (exists != null) { if (replace) { // Delete First toDelete.Add(exists); toAdd.Add(obj); } // Silently ignore duplicate inserts only... } else { toAdd.Add(obj); } }); // Delete First foreach (var obj in toDelete) obj.AllowDelete = true; GameServer.Database.DeleteObject(toDelete); // Then Insert var previousAllowAdd = toAdd.Select(obj => obj.AllowAdd).ToArray(); foreach (var obj in toAdd) obj.AllowAdd = true; GameServer.Database.AddObject(toAdd); // Reset Allow Add Flag var current = 0; foreach (var obj in toAdd) { obj.AllowAdd = previousAllowAdd[current]; current++; } } else { if (log.IsWarnEnabled) log.WarnFormat("XML Package {0} Found Empty, may be a parsing Error...", packageName); result = false; } } catch (Exception e) { if (log.IsErrorEnabled) log.ErrorFormat("Error While Loading XML Package {0} into Database (Mode:{1}) - {2}", packageName, replace ? "Replace" : "Insert", e); result = false; } return result; }
/// <summary> /// Saves Persisted DataObjects into Database /// </summary> /// <param name="dataObjects">DataObjects to Save</param> /// <param name="tableHandler">Table Handler for the DataObjects Collection</param> /// <returns>True if objects were saved successfully; false otherwise</returns> protected override IEnumerable <bool> SaveObjectImpl(DataTableHandler tableHandler, IEnumerable <DataObject> dataObjects) { var success = new List <bool>(); if (!dataObjects.Any()) { return(success); } try { // Columns Filtering out ReadOnly var columns = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey == null && bind.ReadOnly == null) .Select(bind => new { Binding = bind, ColumnName = string.Format("`{0}`", bind.ColumnName), ParamName = string.Format("@{0}", bind.ColumnName) }).ToArray(); // Primary Key var primary = tableHandler.FieldElementBindings.Where(bind => bind.PrimaryKey != null) .Select(bind => new { Binding = bind, ColumnName = string.Format("`{0}`", bind.ColumnName), ParamName = string.Format("@{0}", bind.ColumnName) }).ToArray(); if (!primary.Any()) { throw new DatabaseException(string.Format("Table {0} has no primary key for saving...", tableHandler.TableName)); } var command = string.Format("UPDATE `{0}` SET {1} WHERE {2}", tableHandler.TableName, string.Join(", ", columns.Select(col => string.Format("{0} = {1}", col.ColumnName, col.ParamName))), string.Join(" AND ", primary.Select(col => string.Format("{0} = {1}", col.ColumnName, col.ParamName)))); var objs = dataObjects.ToArray(); var parameters = objs.Select(obj => columns.Concat(primary).Select(col => new QueryParameter(col.ParamName, col.Binding.GetValue(obj)))); var affected = ExecuteNonQueryImpl(command, parameters); var resultByObjects = affected.Select((result, index) => new { Result = result, DataObject = objs[index] }); foreach (var result in resultByObjects) { if (result.Result > 0) { result.DataObject.Dirty = false; result.DataObject.IsPersisted = true; success.Add(true); } else { if (Log.IsErrorEnabled) { if (result.Result < 0) { Log.ErrorFormat("Error saving data object in table {0} Object = {1} --- constraint failed? {2}", tableHandler.TableName, result.DataObject, command); } else { Log.ErrorFormat("Error saving data object in table {0} Object = {1} --- keyvalue changed? {2}\n{3}", tableHandler.TableName, result.DataObject, command, Environment.StackTrace); } } success.Add(false); } } } catch (Exception e) { if (Log.IsErrorEnabled) { Log.ErrorFormat("Error while saving data object in table: {0}\n{1}", tableHandler.TableName, e); } } return(success); }
/// <summary> /// Retrieve a Collection of DataObjects from database based on their primary key values /// </summary> /// <param name="tableHandler">Table Handler for the DataObjects to Retrieve</param> /// <param name="keys">Collection of Primary Key Values</param> /// <returns>Collection of DataObject with primary key matching values</returns> protected abstract IEnumerable <DataObject> FindObjectByKeyImpl(DataTableHandler tableHandler, IEnumerable <object> keys);
/// <summary> /// Check for Table Existence, Create or Alter accordingly /// </summary> /// <param name="table">Table Handler</param> public abstract void CheckOrCreateTableImpl(DataTableHandler table);
public void TestMultiIndexesDataObject() { var dth = new DataTableHandler(typeof(TestTableWithMultiIndexes)); Assert.DoesNotThrow(() => Database.CheckOrCreateTableImpl(dth), "Registering Test Table with Overlapping Indexes should not Throw exceptions."); }