Original Post
in .NET, is there a way to reflect upon what method is calling another method? Say ClassA.MethodA() calls ClassB.MethodB(), is there any way for MethodB to know it was MethodA that called it? This question is motivated by the dubious sort of ORM system I've created: This may or may not seem sort of crazy, but it's neat because it lets me do this in implementing classes: This works because we dictate at a project level that the fields of the "SiteUsageBasic" class have to match the columns of whatever the "SearchSiteUsage" stored procedure returns. It works fine, but I want it to be even easier to use (I have a jr. programmer who is a bit dodgy on his programming skills). How can I make it to where we don't have to explicitly instantiate the SqlParameter objects? If I can figure that out, then the data access stuff is a full abstraction away from the underlying database system. Some possible solutions: 1. Use the varargs list to alternate param name and param value, and iterate over it by twos. It would look like this:
// these classes are in a common utility library
public abstract class DataAdapter<T> where T : new()
{
public virtual T Load(DataRow row)
{
T inst = default(T);
if (row != null)
{
FieldInfo[] fields = typeof(T).GetFields();
inst = new T();
// values get mapped based on reflected field name
foreach (FieldInfo field in fields)
if (row.Table.Columns.Contains(field.Name))
field.SetValue(inst, row[field.Name]);
}
return inst;
}
}
public abstract class DataAccess
{
// variable length argument list FTW
protected List<T> GetList<T>(string procName, params SqlParameter[] parameters)
where T : DataAdapter<T>, new()
{
List<T> list = new List<T>();
//this code is actually refactored differently from here, this is just a canonical example
using (DataSet set = new DataSet())
{
using (SqlCommand command = ConstructCommand(procName, parameters))
{
SqlCommand command = new SqlCommand();
command.Connection = sql;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = procName;
// feeding parameters into the stored procedure command
if (parameters != null)
foreach (SqlParameter parameter in parameters)
if (parameter.Value != null)
command.Parameters.Add(parameter);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
adapter.Fill(set);
}
if (set != null && set.Tables.Count > 0 && set.Tables[0].Rows.Count > 0;)
foreach (DataRow row in set.Tables[0].Rows)
list.Add(new T().Load(row));
}
return list;
}
}
//these classes are in a project that uses the utility library
public class SiteUsageBasic : DataAdapter<SiteUsageBasic>
{
public int SiteUsageRecordID; // concrete class is very simple
public string Email, CraneModel;
public DateTime SearchDate;
}
public class ConcreteDataAccess : DataAccess
{
public List<SiteUsageBasic> SearchSiteUsage(string email, int modelID, DateTime start, DateTime end)
{
// how can we make it to where we don't have to explicitly instantiate the SqlParameter objects?
return GetList<SiteUsageBasic>("SearchSiteUsage",
new SqlParameter("@Email", email),
new SqlParameter("@ModelID", modelID),
new SqlParameter("@DateStart", start),
new SqlParameter("@DateEnd", end));
}
}
GetList<SiteUsageBasic>("SearchSiteUsage",
"@Email", email,
"@ModelID", modelID,
"@DateStart", start,
"@DateEnd", end);
this is kind of yick 2. query the DB for the stored procedures it has, with params, and procedure records in a Dictionary. Use this to construct the order of parameters. It would look like this:
GetList<SiteUsageBasic>("SearchSiteUsage",
email,
modelID,
start,
end);
This is better, but not quite there. 3. somehow reflect over the ConcreteDataAccess class' method calls' names and parameters to automatically fill in SP name and parameter names. It would look like this:
GetList<SiteUsageBasic>(email, modelID, start, end);
If I had a system like this, I could mandate on the project level that the calling method name would have to match a name of a Stored Procedure, and its parameters would have to match the parameters for the stored procedure. However, I don't know if its possible for GetList to know what method is calling it.