2

I am new to Dapper and Dapper.Contrib. There is a class like this and there is a table in database with the same name:

public class Ware
{        
    public int ID { get; set; }
    public string Name { get; set; }
    public short UnitID { get; set; }
    public short TypeID { get; set; }
    public int CableCodeID { get; set; }
    public string Tag1 { get; set; }
    public string Tag2 { get; set; }
    public bool Discontinued { get; set; }
    public decimal Stock { get; set; } //this is not in database. this is helper
    public string UnitCaption { get; set; } //this is not in database. this is helper
    public string TypeCaption { get; set; } //this is not in database. this is helper
    public string FullCaption //this is not in database. this is helper
    {
        get
        {
            return $"{ID} {Name}";
        }
    }
}

I need to Update a whole list of this class to database. I use:

conection.Update(myList); // myList is List<Ware>

But it has an error when it run's:

System.Data.SqlClient.SqlException: 'Invalid column name 'Stock'.'
System.Data.SqlClient.SqlException: 'Invalid column name 'UnitCaption'.'
System.Data.SqlClient.SqlException: 'Invalid column name 'TypeCaption'.'
System.Data.SqlClient.SqlException: 'Invalid column name 'FullCaption'.'

How to fix this?

G Davison
  • 1,079
  • 1
  • 14
  • 21
vaheeds
  • 2,594
  • 4
  • 26
  • 36
  • Check [this](http://stackoverflow.com/a/26766350/1559611), Dapper.Contrib has an option to mark the property as Computed and thus ignore it – Mrinal Kamboj Apr 04 '17 at 05:45
  • There is also `[Write(true/false)]` attribute. Can you explain what is the difference between `[Computed]` and `[Write(true/false)]`? – vaheeds Apr 04 '17 at 06:42
  • 1
    What you need to ignore is `[Computed]`, other one will take care whether property can be updated or not (true / false), as values are sent to the database for DML – Mrinal Kamboj Apr 04 '17 at 07:47
  • from https://github.com/StackExchange/Dapper/tree/master/Dapper.Contrib `[Write(true/false)]` - this property is (not) writeable `[Computed]` - this property is computed and should not be part of updates. I have an extra field in my class that I don't need in DB, what should I use? – vaheeds Apr 10 '17 at 05:51
  • In my view you have misunderstood the working of the APIs provided , since the `[Computed]` is meant for the Helper properties that you are calculating, nonetheless, please try using code, which ever works for your use case – Mrinal Kamboj Apr 10 '17 at 07:29

1 Answers1

2

Copying the code from Dapper.Contrib source code:

Computed

    [AttributeUsage(AttributeTargets.Property)]
    public class ComputedAttribute : Attribute { }

Usage of Computed in code:

private static List<PropertyInfo> ComputedPropertiesCache(Type type)
{
            IEnumerable<PropertyInfo> pi;
            if (ComputedProperties.TryGetValue(type.TypeHandle, out pi))
            {
                return pi.ToList();
            }

            var computedProperties = TypePropertiesCache(type).Where(p => p.GetCustomAttributes(true).Any(a => a is ComputedAttribute)).ToList();

            ComputedProperties[type.TypeHandle] = computedProperties;
            return computedProperties;
}

Now Insert<T> and Update<T> has following code:

var computedProperties = ComputedPropertiesCache(type);

var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList();

Now allPropertiesExceptKeyAndComputed is processed in the code further.

WriteAttribute

 public class WriteAttribute : Attribute
 {
    public WriteAttribute(bool write)
    {
       Write = write;
    }
    public bool Write { get; }
}

Usage of IsWriteable in code:

 private static List<PropertyInfo> TypePropertiesCache(Type type)
 {
    IEnumerable<PropertyInfo> pis;
    if (TypeProperties.TryGetValue(type.TypeHandle, out pis))
    {
       return pis.ToList();
    }

    var properties = type.GetProperties().Where(IsWriteable).ToArray();
    TypeProperties[type.TypeHandle] = properties;
    return properties.ToList();
 }

 private static bool IsWriteable(PropertyInfo pi)
 {
     var attributes = pi.GetCustomAttributes(typeof(WriteAttribute), false).AsList();
     if (attributes.Count != 1) return true;

     var writeAttribute = (WriteAttribute)attributes[0];
     return writeAttribute.Write;
 }

Now notice the function ComputedPropertiesCache pasted above for Computed it calls the method TypePropertiesCache, thus what would happen is, it will exclude both the properties (Write("false") and Computed), however Write attribute is meant for excluding the Type property from Caching, which is creates using ConcurrentDictionary, Its Computed, which is ideally meant for your use case. Hope it helps as expected.

Mrinal Kamboj
  • 11,300
  • 5
  • 40
  • 74