// Uses annotations to provide a generic read function to all proper DataObjects protected void GenericRead(IDataObject targetObject) { if (targetObject == null) { throw new ArgumentNullException("targetObject"); } SqlBackedClassAttribute dataManagementAttribute = (SqlBackedClassAttribute)Attribute.GetCustomAttribute(targetObject.GetType(), typeof(SqlBackedClassAttribute)); if (dataManagementAttribute == null) { throw new ArgumentException("The given object does not have the required SqlBackedClassAttribute."); } // TODO this is ugly ProcedureParameter idParameter = default(ProcedureParameter); GetFieldsAndProperties(targetObject.GetType(), (field, getter) => { if (idParameter.Name != null) { // No need to search further return; } StoredDataAttribute sqlFieldAttribute = (StoredDataAttribute)Attribute.GetCustomAttribute(field, typeof(StoredDataAttribute)); if (sqlFieldAttribute == null || Attribute.GetCustomAttribute(field, typeof(PrimaryKeyAttribute)) == null) { return; } // Found the ID column idParameter = new ProcedureParameter(sqlFieldAttribute.StoredName ?? field.Name, targetObject.ID); }); // Run the actual update DataTable results = _database.RunProcedure(dataManagementAttribute.GetByIdProcedureName, idParameter); if (results.Rows.Count == 0) { throw new IDNotFoundException("The given ID does not correspond to a record."); } else if (results.Rows.Count > 1) { throw new System.Data.DuplicateNameException("The given ID is ambiguous."); } // Update the data in the object InitializeData(targetObject, results.Rows[0]); }
// Uses annotations to provide a generic update function to all proper DataObjects protected void GenericUpdate(IDataObject targetObject) { if (targetObject == null) { throw new ArgumentNullException("targetObject"); } if (!targetObject.IsStoredData) { // Object does not already exist in SQL throw new ArgumentException("The given object is not SQL backed; that is, it does not exist in SQL yet."); } SqlBackedClassAttribute dataManagementAttribute = (SqlBackedClassAttribute)Attribute.GetCustomAttribute(targetObject.GetType(), typeof(SqlBackedClassAttribute)); if (dataManagementAttribute == null) { throw new ArgumentException("The given object does not have the required SqlBackedClassAttribute."); } List <ProcedureParameter> parameters = new List <ProcedureParameter>(); GetFieldsAndProperties(targetObject.GetType(), (field, getter) => { StoredDataAttribute sqlFieldAttribute = (StoredDataAttribute)Attribute.GetCustomAttribute(field, typeof(StoredDataAttribute)); if (sqlFieldAttribute == null) { // Continue return; } // Don't write read-only properties if (field.GetCustomAttribute <DataPropertyAttribute>() != null) { // Continue return; } ProcedureParameter param = new ProcedureParameter(sqlFieldAttribute.StoredName ?? field.Name, getter(targetObject) ?? DBNull.Value); //if (sqlFieldAttribute.DataType.HasValue) //{ // // If the data type is manually specified // param.DbType = sqlFieldAttribute.DataType.Value; //} parameters.Add(param); }); // Run the actual update _database.RunNonQueryProcedure(dataManagementAttribute.UpdateProcedureName, parameters.ToArray()); }
/// <summary> /// Modifies the given object to match the data given in the specified DataRow. /// </summary> public static void InitializeData(IDataObject targetObject, DataRow data) { SqlBackedClassAttribute dataManagementAttribute = (SqlBackedClassAttribute)Attribute.GetCustomAttribute(targetObject.GetType(), typeof(SqlBackedClassAttribute)); if (dataManagementAttribute == null) { throw new ArgumentException("The given object does not have the required SqlBackedClassAttribute."); } SetFieldsAndProperties(targetObject.GetType(), (field, setter) => { StoredDataAttribute sqlFieldAttribute = null; if ((sqlFieldAttribute = Attribute.GetCustomAttribute(field, typeof(StoredDataAttribute)) as StoredDataAttribute) == null) { return; } // Found a SQL column object dataInstance = data[sqlFieldAttribute.StoredName ?? field.Name]; ForeignKeyAttribute fkey = null; if ((fkey = Attribute.GetCustomAttribute(field, typeof(ForeignKeyAttribute)) as ForeignKeyAttribute) != null && fkey.ForeignType == GetMemberType(field)) { // Get the object by ID and use that to set the field // We have to use reflection to invoke a generic method with a type only known at runtime // TODO strongly type the method names throw new NotSupportedException("The static InitializeData method does not support object-type foreign keys."); //field.SetValue(targetObject, this.GetType().GetMethod("GetObjectByID").MakeGenericMethod(fkey.ForeignType).Invoke(this, new object[]{dataInstance})); } else { // Set the field directly setter(targetObject, dataInstance is DBNull ? null : dataInstance); } }); SetObjectInternals(targetObject, targetObject.ID, true); }
public void SaveObject(IDataObject target) { SqlBackedClassAttribute dataAttr = Attribute.GetCustomAttribute(target.GetType(), typeof(SqlBackedClassAttribute)) as SqlBackedClassAttribute; if (dataAttr == null) { throw new InvalidOperationException("SqlBackedClassAttribute not found on the type of the given object."); } if (dataAttr.InsertProcedureName == null && dataAttr.UpdateProcedureName == null) { throw new ReadOnlyException("The given object type is read only."); } if (target.IsStoredData) { GenericUpdate(target); } else { GenericInsert(target); } }
// Uses annotations to provide a generic insert function to all proper DataObjects protected void GenericInsert(IDataObject targetObject) { if (targetObject == null) { throw new ArgumentNullException("targetObject"); } SqlBackedClassAttribute dataManagementAttribute = (SqlBackedClassAttribute)Attribute.GetCustomAttribute(targetObject.GetType(), typeof(SqlBackedClassAttribute)); if (dataManagementAttribute == null) { throw new ArgumentException("The given object does not have the required SqlBackedClassAttribute."); } List <ProcedureParameter> parameters = new List <ProcedureParameter>(); string idColumnName = null; GetFieldsAndProperties(targetObject.GetType(), (field, getter) => { StoredDataAttribute sqlFieldAttribute = (StoredDataAttribute)Attribute.GetCustomAttribute(field, typeof(StoredDataAttribute)); if (sqlFieldAttribute == null) { // Continue return; } if (field.GetCustomAttribute <DataPropertyAttribute>() != null) { // Continue return; } if (Attribute.GetCustomAttribute(field, typeof(PrimaryKeyAttribute)) != null) { // Set ID and handle specially idColumnName = sqlFieldAttribute.StoredName ?? field.Name; return; } // Found a non-ID column ProcedureParameter param = new ProcedureParameter(sqlFieldAttribute.StoredName ?? field.Name, getter(targetObject) ?? DBNull.Value); //if (sqlFieldAttribute.DataType.HasValue) //{ // // If the data type is manually specified // param.DbType = sqlFieldAttribute.DataType.Value; //} parameters.Add(param); }); // Run the actual insert, returns the inserted record DataTable insertedRecords = _database.RunProcedure(dataManagementAttribute.InsertProcedureName, parameters.ToArray()); if (insertedRecords.Rows.Count != 1) { throw new DataException(string.Format("{0} rows were inserted when only one should have been.", insertedRecords.Rows.Count)); } DataRow insertedRecord = insertedRecords.Rows[0]; if (idColumnName == null) { throw new ArgumentException("The specified object does not have an explicitly specified ID column."); } SetObjectInternals(targetObject, (int)insertedRecord[idColumnName], true); }