Entity Framework - How to reference a column name using a string variable

c# entity-framework-6

Question

I have a table called "Account." Account has 3 columns: id, acct_name, is_privileged. When I write something like "account.", visual studio provides me with a list of attributes/methods I can use. Hence, I get the option of using account.id, account.acct_name, and account.is_privileged.

However, I would like to change a particular column's value dynamically, without typing in my column's name. I am getting the column's name dynamically as a string variable. Is it possible to achieve it? If so, how?

My code is as follows:

set_col_name = rowRule.Cells["setcolumnnameDataGridViewTextBoxColumn"].Value.ToString();
set_col_value = rowRule.Cells["setcolumnvalueDataGridViewTextBoxColumn"].Value.ToString();

foreach (DataGridViewRow rowAcc in dgvAccount.Rows)
{
    if (isComparable(rowAcc.Cells[col_name].Value.ToString(), comp_operator, col_value))
    {

        account.id = (int)rowAcc.Cells["idDataGridViewTextBoxColumn2"].Value;
        using (ae = new AccountEntities())
        {
            var temp = ae.Accounts.SingleOrDefault(a => a.id == account.id);
            temp.is_privileged = set_col_value; //learn how to do this dynamically
            ae.SaveChanges();
        }

    }
}

Where I do temp.is_privileged, I'd like to achieve something like, temp."set_col_name" = set_col_value; Instead of specifying the column name directly as being "is_privileged" in this case, I'd like to pass a string to specify it.

Thank you.

1
0
1/13/2020 2:43:11 AM

Accepted Answer

If I understand your problem statement correctly, you want something like this to work:

Account temp = // with temp coming from a library such as EntityFramework
temp.SetValue(set_col_name, set_col_value);

this is quite easy to achieve with either pure reflection or Linq Expression Trees (which I opted for):

static class Ext
{
    public static void Set<T, TProperty>(this T instance, string propertyName, TProperty value)
    {
        var instanceExpression = Expression.Parameter(typeof(T), "p");
        var propertyGetterExpression = Expression.PropertyOrField(instanceExpression, propertyName);

        //generate setter
        var newValueExpression = Expression.Parameter(typeof(TProperty), "value");
        var assignmentExpression = Expression.Assign(propertyGetterExpression, newValueExpression);
        var lambdaExpression = Expression.Lambda<Action<T, TProperty>>(assignmentExpression, instanceExpression, newValueExpression);
        var setter = lambdaExpression.Compile();// the generated lambda will look like so: (p, value) => p.{your_property_name} = value;
        setter(instance, value);
    }
}

one advantage of this method over pure reflection is that you can build the setter delegate once and call it multiple times at later stage (I will leave this with you to experiment)

with the above in place, hopefully you should be able to do something like this:

    var set_col_name = "is_privileged";
    var set_col_value = true;
    using (ae = new AccountEntities())
    {
        var temp = ae.Accounts.SingleOrDefault(a => a.id == account.id);
        temp.Set(set_col_name, set_col_value);
        temp.Set("acct_name", "test");
        ae.SaveChanges();
    }
0
1/13/2020 8:05:49 AM

Popular Answer

You need some reflection in this one. For example

   public static void CopyValues<T>(T obj1, T obj2)
    {
        var type = typeof(T);
        foreach (var prop in type.GetProperties())
        {
            prop.SetValue(obj1, prop.GetValue(obj2));
        }
    }

And use the above function like this:

        var source =  new Accounts(){is_privileged = false};
        var destiny =  new Accounts();

        CopyValues(source, destiny);

It depends of what you are loking for, but the key is to use REFLECTION!



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow