0

I have a little algo I wrote to compare the Linq DataContext table to the sql table. It rolls through the properties of the Linq table and gets the CustomeAttributes of the property, (table columns). It's been working for years, but somebody created a table field with a # sign in it, (UPS#). Linq doesn't like such a name for its properties for obvious reasons. So, it has a member of the ColumnAttribute called "Name" to handle the swap. But, I've always used the "Storage" member for my column name. You would think you would just pick up the "Name" member if it's present, but I can't find it to save my life.

This is the code. Any help is very much appreciated.

public static ColumnInfo[] GetColumnsInfo(Type linqTableClass)
    {
        // Just looking in the loop to see if I missed something.
        foreach (var fld in linqTableClass.GetProperties())
        {
            foreach (var attr in fld.CustomAttributes)
            {
                foreach (var arg in attr.NamedArguments)
                {
                    if (arg.MemberName == "Name")
                        Debug.WriteLine(arg.MemberName);

                    Debug.WriteLine("{0}", arg.MemberName);
                }
            }
        }

        var columnInfoQuery =
            from field in linqTableClass.GetProperties()
            from attribute in field.CustomAttributes
            from namedArgument in attribute.NamedArguments
            where namedArgument.MemberName == "DbType"
            select new ColumnInfo
            {
                //ColumnName = field.Name,
                ColumnName = namedArgument.MemberName,
                DatabaseType = namedArgument.TypedValue.Value.ToString(),
            };
        return columnInfoQuery.ToArray();
    }

and this is the property in the Table Class:

[global::System.Data.Linq.Mapping.ColumnAttribute(Name="PEER_UPS#", Storage="_PEER_UPS_", DbType="Char(31) NOT NULL", CanBeNull=false)]
    public string PEER_UPS_
    {
        get
        {
            return this._PEER_UPS_;
        }
        set
        {
            if ((this._PEER_UPS_ != value))
            {
                this.OnPEER_UPS_Changing(value);
                this.SendPropertyChanging();
                this._PEER_UPS_ = value;
                this.SendPropertyChanged("PEER_UPS_");
                this.OnPEER_UPS_Changed();
            }
        }
    }
Greg Kowieski
  • 119
  • 1
  • 9
  • Hi, why aren't you using CustomAttributes.OfType() or .GetCustomAttributes(typeof(ColumnAttribute)) ? Then you simply can do attr.Name and remove one foreach... – Marco Feb 02 '18 at 13:48

3 Answers3

0

and here is what i suggest:

[sorry, my first example was indeed too simplistic] Here is how i'd do it:

namespace LinqAttributes
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;

    public class ColumnInfo
    {
        public string ColumnName { get; set; }
        public string DatabaseType { get; set; }
    }

    public class Test
    {
        [System.Data.Linq.Mapping.ColumnAttribute(Name = "Whatever", Storage = "Whatever", DbType = "Char(20)", CanBeNull = true)]
        public string MyProperty { get; set; }

        [System.Data.Linq.Mapping.ColumnAttribute(Name = "PEER_UPS#", Storage = "_PEER_UPS_", DbType = "Char(31) NOT NULL", CanBeNull = false)]
        public string PEER_UPS_ { get; set; }
    }

    internal class Program
    {
        public static IEnumerable<ColumnInfo> GetColumnsInfo(Type type)
        {
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(type))
            {
            var columnAttribute = descriptor.Attributes
                .OfType<System.Data.Linq.Mapping.ColumnAttribute>().SingleOrDefault();
            if (columnAttribute != null)
            {
                yield return new ColumnInfo
                {
                    ColumnName = columnAttribute.Name,
                    DatabaseType = columnAttribute.DbType
                };
             }
            }
        }

        private static void Main(string[] args)
        {
            foreach (var item in GetColumnsInfo(typeof(Test)))
            {
                Debug.WriteLine(item.ColumnName);
            }            
        }
    }
}

Just tested it. Cheers!

Marco
  • 984
  • 10
  • 18
  • That didn't come back with any results. For the life of me I can't see why not either since fld.GetCustomAttributesData().Cast().Where(r => r.AttributeType == typeof(ColumnAttribute)) does. I had to write a really ugly method to get the right results. not my proudest moment but It got the job done. – Greg Kowieski Feb 12 '18 at 19:33
  • I'm swamped to the gills. As soon as I get a chance I'll try it out. – Greg Kowieski Feb 15 '18 at 03:18
0

I couldn't find a pretty way to get this done. For some reason the ColumnAttribute just didn't want to play nice. Ugly as this is, it works.

public class ColumnInfo
{
    public string ColumnName { get; set; }
    public string DatabaseType { get; set; }
}

public static IEnumerable<ColumnInfo> GetColumnsInfo(Type linqTableClass)
    {
        Debug.WriteLine(string.Format("Table: {0}", linqTableClass.Name));

        /// In-Case this has to grow in the future.  Using a list for the arg names to search for.  
        /// The primary arg should be in position 0 of the array.
        string dbTypeArgName = "DbType";
        string fldPrimayName = "Storage";
        string fldSecondaryName = "Name";
        List<string> fldArgnames = new List<string>() { fldPrimayName, fldSecondaryName };

        foreach (var fld in linqTableClass.GetProperties())
        {
            Debug.WriteLine(string.Format("Field Name: {0}", fld.Name));

            foreach (var attr in fld.GetCustomAttributesData().Cast<CustomAttributeData>()
                .Where(r => r.AttributeType == typeof(ColumnAttribute))
                .Where(a => a.NamedArguments
                    .Select(n => n.MemberName)
                    .Intersect(fldArgnames)
                    .Any()))
            {
                var fldName = attr.NamedArguments.Where(r => r.MemberName == fldSecondaryName).Count() != 0
                        ? attr.NamedArguments.Where(r => r.MemberName == fldSecondaryName).SingleOrDefault().TypedValue.Value.ToString()
                        : fld.Name;
                var fldType = attr.NamedArguments
                        .Where(r => r.MemberName == dbTypeArgName)
                        .Select(r => r.TypedValue.Value.ToString())
                        .SingleOrDefault();

                Debug.WriteLine(string.Format("\tTable Field Name {0} Table Type {1}", fldName, fldType));

                yield return new ColumnInfo()
                {
                    ColumnName = fldName,
                    DatabaseType = fldType,
                };
            }
        }
    }
Greg Kowieski
  • 119
  • 1
  • 9
0
public class City
{
    public City() { }

    [Column("id_city")]
    public int Id { get; private set; }
}

var obj = new City();
var pro = obj.GetType().GetProperties();

string columnAttribute = pro.GetCustomAttributes<ColumnAttribute>().FirstOrDefault().Name;

if(columnAttribute == "id_city") {
    //sucess
}