예제 #1
0
        /// <summary>
        /// Replaces all string representations destined to end up in DateTime or TimeSpan fields in the target database
        /// into hard typed objects (using <see cref="DateTimeDecider"/>)
        /// </summary>
        /// <param name="dt"></param>
        protected void ConvertStringDatesToDateTime(DataTable dt)
        {
            var dict = GetMapping(dt.Columns.Cast <DataColumn>(), out _);

            //for each column in the destination
            foreach (var kvp in dict)
            {
                //if the destination column is a date based column
                var dataType = kvp.Value.DataType.GetCSharpDataType();
                if (dataType == typeof(DateTime) || dataType == typeof(TimeSpan))
                {
                    //if it's already not a string then that's fine (hopefully its a DateTime!)
                    if (kvp.Key.DataType != typeof(string))
                    {
                        continue;
                    }

                    //create a new column hard typed to DateTime
                    var newColumn = dt.Columns.Add(kvp.Key.ColumnName + "_" + Guid.NewGuid().ToString(), dataType);

                    //guess the DateTime culture based on values in the table
                    DateTimeDecider.GuessDateFormat(dt.Rows.Cast <DataRow>().Take(500).Select(r => r[kvp.Key] as string));

                    foreach (DataRow dr in dt.Rows)
                    {
                        //parse the value

                        var val = DateTimeDecider.Parse(dr[kvp.Key] as string) ?? DBNull.Value;
                        if (dataType == typeof(DateTime))
                        {
                            dr[newColumn] = val;
                        }
                        else
                        {
                            dr[newColumn] = val == DBNull.Value? val:((DateTime)val).TimeOfDay;
                        }
                    }

                    //if the DataColumn is part of the Primary Key of the DataTable (in memory)
                    //then we need to update the primary key to include the new column not the old one
                    if (dt.PrimaryKey != null && dt.PrimaryKey.Contains(kvp.Key))
                    {
                        dt.PrimaryKey = dt.PrimaryKey.Except(new [] { kvp.Key }).Union(new [] { newColumn }).ToArray();
                    }

                    //drop the original column
                    dt.Columns.Remove(kvp.Key);

                    //rename the hard typed column to match the old column name
                    newColumn.ColumnName = kvp.Key.ColumnName;
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Replaces all string representations for data types that can be problematic/ambiguous (e.g. DateTime or TimeSpan)
        ///  into hard typed objects using appropriate decider e.g. <see cref="DateTimeDecider"/>.
        /// </summary>
        /// <param name="dt"></param>
        protected void ConvertStringTypesToHardTypes(DataTable dt)
        {
            var dict = GetMapping(dt.Columns.Cast <DataColumn>(), out _);

            var factory = new TypeDeciderFactory(Culture);

            //These are the problematic Types
            Dictionary <Type, IDecideTypesForStrings> deciders = factory.Dictionary;

            //for each column in the destination
            foreach (var kvp in dict)
            {
                //if the destination column is a problematic type
                var dataType = kvp.Value.DataType.GetCSharpDataType();
                if (deciders.ContainsKey(dataType))
                {
                    //if it's already not a string then that's fine (hopefully its a legit Type e.g. DateTime!)
                    if (kvp.Key.DataType != typeof(string))
                    {
                        continue;
                    }

                    //create a new column hard typed to DateTime
                    var newColumn = dt.Columns.Add(kvp.Key.ColumnName + "_" + Guid.NewGuid().ToString(), dataType);

                    var decider = deciders[dataType];

                    //if it's a DateTime decider then guess DateTime culture based on values in the table
                    if (decider is DateTimeTypeDecider)
                    {
                        //also use this one incase the user has set up explicit stuff on it e.g. Culture/Settings
                        decider = DateTimeDecider;
                        DateTimeDecider.GuessDateFormat(dt.Rows.Cast <DataRow>().Take(500).Select(r => r[kvp.Key] as string));
                    }


                    foreach (DataRow dr in dt.Rows)
                    {
                        try
                        {
                            //parse the value
                            dr[newColumn] = decider.Parse(dr[kvp.Key] as string) ?? DBNull.Value;
                        }
                        catch (Exception ex)
                        {
                            throw new Exception($"Failed to parse value '{dr[kvp.Key]}' in column '{kvp.Key}'", ex);
                        }
                    }

                    //if the DataColumn is part of the Primary Key of the DataTable (in memory)
                    //then we need to update the primary key to include the new column not the old one
                    if (dt.PrimaryKey != null && dt.PrimaryKey.Contains(kvp.Key))
                    {
                        dt.PrimaryKey = dt.PrimaryKey.Except(new [] { kvp.Key }).Union(new [] { newColumn }).ToArray();
                    }

                    var oldOrdinal = kvp.Key.Ordinal;

                    //drop the original column
                    dt.Columns.Remove(kvp.Key);

                    //rename the hard typed column to match the old column name
                    newColumn.ColumnName = kvp.Key.ColumnName;
                    if (oldOrdinal != -1)
                    {
                        newColumn.SetOrdinal(oldOrdinal);
                    }
                }
            }
        }