public static int GenericDelete <T>(string tableName, T Obj, SqlConnection sqlCon = null, SqlTransaction sqlTran = null) { int result; bool useOutsideConnection = true; //indatictor of outside connection received string PKcolumnName; //hold primary key column name Type type = typeof(T); PropertyInfo[] propertiesWithPK = type.GetProperties();//get properties from newObj PKcolumnName = propertiesWithPK[0].Name; //------------------------------------------------------------- PropertyInfo[] propertiesExceptPK = propertiesWithPK.Skip(1).ToArray();//skip the primary key, as we don't need to insert PK //------------------------------------------------------------- //if no outside connection received, set indatictor to false, then start the connection. if (sqlCon == null) { useOutsideConnection = false; sqlCon = DBObject.GetConnection(); } //prepare the sql syntax for Where for concurrency check StringBuilder FieldToSqlWhere = new StringBuilder(); foreach (PropertyInfo property in propertiesExceptPK) { FieldToSqlWhere.Append(property.Name + "=@" + property.Name) .Append(" AND "); } FieldToSqlWhere.Length = FieldToSqlWhere.Length - 5;//remove the last " AND " //Insert Statement string deleteStatement = "DELETE FROM " + tableName + " WHERE " + FieldToSqlWhere; SqlCommand cmd = new SqlCommand(deleteStatement, sqlCon); //if outside transcation passed in, bound the sql command with the transcation if (sqlTran != null) { cmd.Transaction = sqlTran; } //bound VALUES foreach (PropertyInfo property in propertiesExceptPK) { if (property.GetValue(Obj) == null) { cmd.Parameters.AddWithValue("@" + property.Name, DBNull.Value); } else { cmd.Parameters.AddWithValue("@" + property.Name, property.GetValue(Obj, null)); } } //if no outsideConnection passed in, open the connection if (!useOutsideConnection) { sqlCon.Open(); //execute the query result = cmd.ExecuteNonQuery(); sqlCon.Close(); } else { //OutsideConnection received, just execute the query,let the outside handle connection open and close result = cmd.ExecuteNonQuery(); } // should return the PK of new inserted record if succeed return(result); }
/// <summary> /// Generic Reading method for get instants of certain Class from corresponding DB Tables /// </summary> /// <typeparam name="T"> Generic Type, could be Products, packages etc. /// ***** the Classes mush have a constructor that takes 0 argument. /// </typeparam> /// <param name="tableName">Corresponding Table Name in DB</param> /// <param name="orderByIndex">how you want to order your results, 1 is default</param> /// <returns>A list of requried entity classes for the corresponding DB </returns> public static List <T> GenericRead <T>(string tableName, int orderByIndex = 1) //need inherit from ParentClass so that I can call the extra method { List <T> classData = new List <T>(); //List to hold result Type type = typeof(T); PropertyInfo[] properties = type.GetProperties();//get field of given class //prepare the Sql Syntax for the query StringBuilder FieldToSqlSyntax = new StringBuilder(); foreach (PropertyInfo property in properties) { FieldToSqlSyntax.Append(property.Name).Append(","); } FieldToSqlSyntax.Length--; //remove the last "," using (SqlConnection connection = DBObject.GetConnection()) //using method could auto close resources, so the connection got closed automatically { //The select Sql Syntax string selectStatement = "SELECT " + FieldToSqlSyntax + " " + "FROM " + tableName + " " + "ORDER BY " + orderByIndex; using (SqlCommand selectCommand = new SqlCommand(selectStatement, connection))//auto close Sqlcommand { connection.Open(); using (SqlDataReader dr = selectCommand.ExecuteReader())//auto close reader { while (dr.Read()) { T tempObj = Activator.CreateInstance <T>(); //temp entity class PropertyInfo[] tempProperties = tempObj.GetType().GetProperties(); //get all the field of this entity class //if T is Products Class, //properties will looks like {ProductID, prodName} foreach (PropertyInfo property in tempProperties) { if (dr[property.Name] != DBNull.Value) { //if the property is nullable, etc "datatime?"(this is a nullable type with datatime type underlying it) //to get the actual type (datatime) out of "datatime?" by calling Nullable.GetUnderlyingType //if the property is not nullable, etc int, then the "??" will return right-side property.propertyType which is "int" since left side is "null". Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; //cast the reader result (Object type) to correct type and then assign the value. //if T is Products Class, It's just like tempObj.ProductID=Convert.toInt32(dr["ProductID"]) property.SetValue(tempObj, Convert.ChangeType(dr[property.Name], t)); } else { //DBNull.Value in DB table, so set the property to null property.SetValue(tempObj, null); } } classData.Add(tempObj);//add temp entity class to the result List } //---------------------------------------------------------------------------- //below is another way that required a constructor with parameters, this does not support default constructor //------------------------------------------------------------------------------ //while (dr.Read()) //{ // List<Object> args = new List<Object>();//an list to hold the required args for certain entityClass // foreach (PropertyInfo property in properties) // { // if (dr[property.Name] != DBNull.Value) // { // //if the property is nullable, etc "datatime?"(this is a nullable type with datatime type underlying it) // //to get the actual type (datatime) out of "datatime?" by calling Nullable.GetUnderlyingType // //if the property is not nullable, etc int, then the "??" will return right-side property.propertyType which is "int" since left side is "null". // Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; // //cast the reader result (Object type) to correct type and then assign the value. // //if T is Products Class, It's just like tempObj.ProductID=Convert.toInt32(dr["ProductID"]) // args.Add(Convert.ChangeType(dr[property.Name], t));//add to the args list // //args.Add(dr[property.Name]); // } // else // { // //DBNull.Value in DB table, so set the property to null // args.Add(null); // } // } // T tempObj = (T)Activator.CreateInstance(typeof(T),args.ToArray());//create an instant of entityClass with args // classData.Add(tempObj);//add temp entity class to the result List //} } } } return(classData);//returen results }
/// <summary> /// /// </summary> /// <typeparam name="T">Generic class /// ***** the Classes mush have a constructor that takes 0 argument. /// </typeparam> /// <param name="tableName">Name of the DB Table</param> /// <param name="newObj"> the new record you want to insert</param> /// <param name="sqlCon">Optional Connection</param> /// <param name="sqlTran">Optional Transcation</param> /// <param name="FieldIndexToCheck">Optional,the index of property names that needed when checking concurrency caused duplicated info againest the existing records in DB </param> /// <returns> the Primary Key value of the new inserted record.</returns> public static int GenericInsert <T>(string tableName, T newObj, SqlConnection sqlCon = null, SqlTransaction sqlTran = null, int[] FieldIndexToCheck = null) { int PKinserted = -1; //PK for new inserted value bool useOutsideConnection = true; //indatictor of outside connection received string PKcolumnName; //hold primary key column name Type type = typeof(T); PropertyInfo[] propertiesWithPK = type.GetProperties(); //get properties from newObj PKcolumnName = propertiesWithPK[0].Name; PropertyInfo[] propToCheckDup; //hold the property names that needed when checking duplicated info againest the existing records in DB //------------------------------------------------------------- PropertyInfo[] propertiesExceptPK = propertiesWithPK.Skip(1).ToArray(); //skip the primary key, as we don't need to insert PK //------------------------------------------------------------- //set checking list according to argument, for example. For packages, we only check name, startDate, endDate. if these 3 property value are the same //then we concern those 2 packages are the same and this duplicate insert should be prevented. if (FieldIndexToCheck != null) { //if passed in, then only check passed in property propToCheckDup = new PropertyInfo[FieldIndexToCheck.Length]; int i = 0; foreach (int id in FieldIndexToCheck) { propToCheckDup[i] = propertiesWithPK[id]; i++; } } else { //default, check all property except PK propToCheckDup = propertiesExceptPK; } //if no outside connection received, set indatictor to false, then start the connection. if (sqlCon == null) { useOutsideConnection = false; sqlCon = DBObject.GetConnection(); } //prepare the sql syntax for Where for concurrency check StringBuilder FieldToSqlWhere = new StringBuilder(); foreach (PropertyInfo property in propToCheckDup) { FieldToSqlWhere.Append(property.Name + "=@" + property.Name) .Append(" AND "); } FieldToSqlWhere.Length = FieldToSqlWhere.Length - 5;//remove the last " AND " //Prepare the Insert Sql Syntax StringBuilder FieldToSqlInsert = new StringBuilder(); FieldToSqlInsert.Append("("); foreach (PropertyInfo property in propertiesExceptPK) { FieldToSqlInsert.Append(property.Name).Append(","); } FieldToSqlInsert.Length--;//remove the last "," FieldToSqlInsert.Append(")"); //prepare the sql syntax for VALUES StringBuilder FieldToSqlValues = new StringBuilder(); FieldToSqlValues.Append("("); foreach (PropertyInfo property in propertiesExceptPK) { FieldToSqlValues.Append("@").Append(property.Name).Append(","); } FieldToSqlValues.Length = FieldToSqlValues.Length - 1;//remove the last "," FieldToSqlValues.Append(")"); //Insert Statement string insertStatement = "IF NOT EXISTS (SELECT 1 FROM " + tableName + " WHERE " + FieldToSqlWhere + ")" + "INSERT INTO " + tableName + FieldToSqlInsert + " OUTPUT INSERTED." + PKcolumnName + " VALUES " + FieldToSqlValues; SqlCommand cmd = new SqlCommand(insertStatement, sqlCon); //if outside transcation passed in, bound the sql command with the transcation if (sqlTran != null) { cmd.Transaction = sqlTran; } //bound VALUES foreach (PropertyInfo property in propertiesExceptPK) { if (property.GetValue(newObj) == null) { cmd.Parameters.AddWithValue("@" + property.Name, DBNull.Value); } else { cmd.Parameters.AddWithValue("@" + property.Name, property.GetValue(newObj, null)); } } //if no outsideConnection passed in, open the connection if (!useOutsideConnection) { sqlCon.Open(); //execute the query PKinserted = Convert.ToInt32(cmd.ExecuteScalar()); // = (int) sqlCon.Close(); } else { //OutsideConnection received, just execute the query,let the outside handle connection open and close PKinserted = (int)cmd.ExecuteScalar(); } // should return the PK of new inserted record if succeed return(PKinserted); }
/// <summary> /// Generic update a record in DB /// </summary> /// <typeparam name="T">Generic class /// ***** the Classes mush have a constructor that takes 0 argument. /// </typeparam> /// <param name="tableName">Name of the DB Table</param> /// <param name="oldObj">the unchanged object for checking concurrency issue</param> /// <param name="newObj">the changed object</param> /// <param name="sqlCon">Optional argument:to receive outside connection so that enable transcation </param> /// <param name="sqlTran">Optional argument:to receive outside transcation so that enable commit or rollback </param> /// <param name="FieldIndexToCheck">Optional,the index of property names that needed when checking concurrency caused duplicated info againest the existing records in DB </param> /// <returns>the number of affect record, should be 1 if succeed</returns> public static int GenericUpdate <T>(string tableName, T oldObj, T newObj, SqlConnection sqlCon = null, SqlTransaction sqlTran = null, int[] FieldIndexToCheck = null) { int count = 0; bool useOutsideConnection = true; //indatictor of outside connection received PropertyInfo[] propToCheckDup; //hold the property names that needed when checking duplicated info againest the existing records in DB Type type = typeof(T); PropertyInfo[] PropertiesWithPK = type.GetProperties(); //get all the field of this entity class //if T is Products Class, //properties will looks like {ProductID, prodName} PropertyInfo[] PropertiesExceptPK = PropertiesWithPK.Skip(1).ToArray(); //skip the primary key, as we don't need to update //set checking list according to argument, for example. For packages, we only check name, startDate, endDate. if these 3 property value are the same //then we concern those 2 packages are the same and this duplicate insert should be prevented. if (FieldIndexToCheck != null) { //if passed in, then only check passed in property propToCheckDup = new PropertyInfo[FieldIndexToCheck.Length]; int i = 0; foreach (int id in FieldIndexToCheck) { propToCheckDup[i] = PropertiesWithPK[id]; i++; } } else { //default, check all property except PK propToCheckDup = PropertiesExceptPK; } //build the where satement used in check concurrey StringBuilder FieldToSqlCheckWhere = new StringBuilder(); foreach (PropertyInfo property in propToCheckDup) { FieldToSqlCheckWhere.Append(property.Name + "=@New" + property.Name) .Append(" AND "); } FieldToSqlCheckWhere.Length = FieldToSqlCheckWhere.Length - 5;//remove the last " AND " bool needToCheckConcurrencyDup = false; //For the concurrenty duplication checking list, if at least one required property's value has been changed then need perform a concurrency dup check. foreach (PropertyInfo property in propToCheckDup) { if (property.GetValue(oldObj) != property.GetValue(newObj)) { needToCheckConcurrencyDup = true; break; } } //if no outside connection received, set indatictor to false, then start the connection. if (sqlCon == null) { useOutsideConnection = false; sqlCon = DBObject.GetConnection(); } //prepare the sql syntax for concurrency check StringBuilder FieldToSqlWhere = new StringBuilder(); foreach (PropertyInfo property in PropertiesWithPK) { FieldToSqlWhere.Append("(" + property.Name + "=@Old" + property.Name + " OR ") .Append(property.Name + " IS NULL AND @Old" + property.Name + " IS NULL)") .Append(" AND "); } FieldToSqlWhere.Length = FieldToSqlWhere.Length - 5;//remove the last " AND " //Prepare the Update Sql Syntax StringBuilder FieldToSqlSet = new StringBuilder(); foreach (PropertyInfo property in PropertiesExceptPK) { FieldToSqlSet.Append(property.Name).Append("=@New").Append(property.Name).Append(","); } FieldToSqlSet.Length--;//remove the last "," SqlCommand cmd; if (needToCheckConcurrencyDup == false) { //no value change for requried property in concurrency checking list string updateStatement = "UPDATE " + tableName + " SET " + FieldToSqlSet + " WHERE " + FieldToSqlWhere; cmd = new SqlCommand(updateStatement, sqlCon); } else { //there are changes amont the value of required property, so perfromed a concurrency check string updateStatement = "IF NOT EXISTS (SELECT 1 FROM " + tableName + " WHERE " + FieldToSqlCheckWhere + ") " + "UPDATE " + tableName + " SET " + FieldToSqlSet + " WHERE " + FieldToSqlWhere; cmd = new SqlCommand(updateStatement, sqlCon); } //if outside transcation passed in, bound the sql command with the transcation if (sqlTran != null) { cmd.Transaction = sqlTran; } //bound @new foreach (PropertyInfo property in PropertiesExceptPK) { if (property.GetValue(newObj) == null) { cmd.Parameters.AddWithValue("@New" + property.Name, DBNull.Value); } else { cmd.Parameters.AddWithValue("@New" + property.Name, property.GetValue(newObj, null)); } } //Bound @old foreach (PropertyInfo property in PropertiesWithPK) { if (property.GetValue(oldObj) == null) { cmd.Parameters.AddWithValue("@Old" + property.Name, DBNull.Value); } else { cmd.Parameters.AddWithValue("@Old" + property.Name, property.GetValue(oldObj, null)); } } //if no outsideConnection passed in, open the connection if (!useOutsideConnection) { sqlCon.Open(); //execute the query count = cmd.ExecuteNonQuery(); sqlCon.Close(); } else { //OutsideConnection received, just execute the query,let the outside handle connection open and close count = cmd.ExecuteNonQuery(); } // should return 1 if succeed return(count); }