Datatable select with multiple conditions

前端 未结 7 1987
再見小時候
再見小時候 2020-12-02 17:03

I have a datatable with 4 columns A, B, C and D such that a particular combination of values for column A, B and C is unique in the datatable.

Objective:

7条回答
  •  无人及你
    2020-12-02 17:32

    If you really don't want to run into lots of annoying errors (datediff and such can't be evaluated in DataTable.Select among other things and even if you do as suggested use DataTable.AsEnumerable you will have trouble evaluating DateTime fields) do the following:

    1) Model Your Data (create a class with DataTable columns)

    Example

    public class Person
    {
    public string PersonId { get; set; }
    public DateTime DateBorn { get; set; }
    }
    

    2) Add this helper class to your code

    public static class Extensions
    {
    /// 
    /// Converts datatable to list dynamically
    /// 
    /// Class name
    /// data table to convert
    /// List
    public static List ToList(this DataTable dataTable) where T : new()
    {
        var dataList = new List();
    
        //Define what attributes to be read from the class
        const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
    
        //Read Attribute Names and Types
        var objFieldNames = typeof(T).GetProperties(flags).Cast().
            Select(item => new
            {
                Name = item.Name,
                Type = Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType
            }).ToList();
    
        //Read Datatable column names and types
        var dtlFieldNames = dataTable.Columns.Cast().
            Select(item => new {
                Name = item.ColumnName,
                Type = item.DataType
            }).ToList();
    
        foreach (DataRow dataRow in dataTable.AsEnumerable().ToList())
        {
            var classObj = new T();
    
            foreach (var dtField in dtlFieldNames)
            {
                PropertyInfo propertyInfos = classObj.GetType().GetProperty(dtField.Name);
    
                var field = objFieldNames.Find(x => x.Name == dtField.Name);
    
                if (field != null)
                {
    
                    if (propertyInfos.PropertyType == typeof(DateTime))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToDateTime(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(int))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToInt(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(long))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToLong(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(decimal))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToDecimal(dataRow[dtField.Name]), null);
                    }
                    else if (propertyInfos.PropertyType == typeof(String))
                    {
                        if (dataRow[dtField.Name].GetType() == typeof(DateTime))
                        {
                            propertyInfos.SetValue
                            (classObj, ConvertToDateString(dataRow[dtField.Name]), null);
                        }
                        else
                        {
                            propertyInfos.SetValue
                            (classObj, ConvertToString(dataRow[dtField.Name]), null);
                        }
                    }
                }
            }
            dataList.Add(classObj);
        }
        return dataList;
    }
    
    private static string ConvertToDateString(object date)
    {
        if (date == null)
            return string.Empty;
    
        return HelperFunctions.ConvertDate(Convert.ToDateTime(date));
    }
    
    private static string ConvertToString(object value)
    {
        return Convert.ToString(HelperFunctions.ReturnEmptyIfNull(value));
    }
    
    private static int ConvertToInt(object value)
    {
        return Convert.ToInt32(HelperFunctions.ReturnZeroIfNull(value));
    }
    
    private static long ConvertToLong(object value)
    {
        return Convert.ToInt64(HelperFunctions.ReturnZeroIfNull(value));
    }
    
    private static decimal ConvertToDecimal(object value)
    {
        return Convert.ToDecimal(HelperFunctions.ReturnZeroIfNull(value));
    }
    
    private static DateTime ConvertToDateTime(object date)
    {
        return Convert.ToDateTime(HelperFunctions.ReturnDateTimeMinIfNull(date));
    }
    
    }
    public static class HelperFunctions
    {
    
    public static object ReturnEmptyIfNull(this object value)
    {
        if (value == DBNull.Value)
            return string.Empty;
        if (value == null)
            return string.Empty;
        return value;
    }
    public static object ReturnZeroIfNull(this object value)
    {
        if (value == DBNull.Value)
            return 0;
        if (value == null)
            return 0;
        return value;
    }
    public static object ReturnDateTimeMinIfNull(this object value)
    {
        if (value == DBNull.Value)
            return DateTime.MinValue;
        if (value == null)
            return DateTime.MinValue;
        return value;
    }
    /// 
    /// Convert DateTime to string
    /// 
    /// 
    /// if true it will execlude time from datetime string. Default is false
    /// 
    public static string ConvertDate(this DateTime datetTime, bool excludeHoursAndMinutes = false)
    {
        if (datetTime != DateTime.MinValue)
        {
            if (excludeHoursAndMinutes)
                return datetTime.ToString("yyyy-MM-dd");
            return datetTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
        }
        return null;
    }
    }
    

    3) Easily convert your DataTable (dt) to a List of objects with following code:

    List persons = Extensions.ToList(dt);
    

    4) have fun using Linq without the annoying row.Field bit you have to use when using AsEnumerable

    Example

    var personsBornOn1980 = persons.Where(x=>x.DateBorn.Year == 1980);
    

提交回复
热议问题