/// <summary>Is this type adorned with any RayAttribute on any property</summary> /// <param name="type"></param> /// <returns></returns> public static bool Marked(Type type) { PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); if (props.Length < 1) { return(false); } foreach (PropertyInfo prop in props) { RayPropertyAttribute map = prop.GetCustomAttributes <RayPropertyAttribute>(false).FirstOrDefault(); if (map != null) { return(true); } } return(false); }
/// <summary>Gets all the destination field names as a list sorted by their order</summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <returns></returns> public static List <string> GetDestinations(Type type, string context = null) { List <Tuple <uint, string> > rec = new List <Tuple <uint, string> >(); PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); if (props.Length < 1) { return(new List <string>()); } foreach (PropertyInfo prop in props) { RayPropertyAttribute map = null; // null context if (String.IsNullOrWhiteSpace(context)) { map = prop.GetCustomAttributes <RayPropertyAttribute>(false).FirstOrDefault(); context = (map != null && !String.IsNullOrWhiteSpace(map.Context)) ? map.Context : null; } else // explicit context { map = prop.GetCustomAttributes <RayPropertyAttribute>(false).Where(a => a.Context.Equals(context, StringComparison.Ordinal)).FirstOrDefault(); } if (map == null) { continue; } if (!String.IsNullOrWhiteSpace(map.Destination) && prop.CanRead) { rec.Add(new Tuple <uint, string>(map.Order, map.Destination)); } } // sort by order return(rec.OrderBy(t => t.Item1).Select(t => t.Item2).ToList <string>()); }
/// <summary>Parses to FieldSource adorned attributes.</summary> /// <typeparam name="T"></typeparam> /// <param name="cursor"></param> /// <param name="context">The context to use to parse, can be null and will use the first FieldSource attribute with no context.</param> /// <returns></returns> private T ParseRecord <T>(SqlDataReader cursor, string context = null) where T : new() { // valid DB record if (cursor == null || !cursor.HasRows) { return(default(T)); } // get ALL the DB field names lowered List <string> fieldNames = Enumerable.Range(0, cursor.FieldCount).Select(cursor.GetName).ToList(); //.ConvertAll( d => d.ToLower() ); // get all the properties in the class PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); if (props.Length < 1) { return(default(T)); } T obj = new T(); // iterate each property foreach (PropertyInfo prop in props) { // can you publicly set the property if (!prop.CanWrite) { continue; } // get the properties FieldMap attribute List <RayPropertyAttribute> sources = prop.GetCustomAttributes <RayPropertyAttribute>(false).ToList(); // if there is not field map source, then this property is not read from the CSV if (sources == null || sources.Count < 1) { continue; } RayPropertyAttribute map = null; // if the context is null - then use the first empty FieldSource if (String.IsNullOrWhiteSpace(context)) { map = sources.Where(s => String.IsNullOrWhiteSpace(s.Context)).FirstOrDefault(); } else { map = sources.Where(s => s.Context.Equals(context, StringComparison.Ordinal)).FirstOrDefault(); } if (map == null || String.IsNullOrWhiteSpace(map.Source)) { continue; } // verify there is a coresponding DB column name if (!fieldNames.Contains(map.Source)) { continue; } cursor.Parse <T>(obj, prop, map.Source); } return(obj); }
/// <summary>Formats the insert statement</summary> /// <param name="obj"></param> /// <param name="props"></param> private SQLiteCommand FormatInsertCommand <T>(T obj, string tableName, IEnumerable <PropertyInfo> props, string ctx) { // if no table or properties then abort if (obj == null || String.IsNullOrWhiteSpace(tableName) || props == null || props.Count() < 1) { return(null); } // determine the context type from the object itself RayContext ctxType = RayPropertyAttribute.CalculateContext(typeof(T), ctx); if (ctxType == RayContext.Error) { throw new System.Exception("A context was specified by no properties have RayAttribute"); } Dictionary <string, SQLiteParameter> paras = new Dictionary <string, SQLiteParameter>(); // set the value of each property on the object foreach (PropertyInfo prop in props) { // dict values string propName = null; SQLiteParameter param = null; // can you publicly read the property if (!prop.CanRead) { continue; } // reject arrays except byte[] if (prop.PropertyType.IsArray && prop.PropertyType != typeof(byte[])) { continue; } // reject most generic Lists for now if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List <>)) { continue; } // property names is determined context type if (ctxType == RayContext.PropertyName) { propName = prop.Name; } else if (ctxType == RayContext.Null) { // get the properties FieldMap attribute RayPropertyAttribute dest = prop.GetCustomAttributes <RayPropertyAttribute>(false).Where(a => a.IsNullContext).FirstOrDefault(); if (dest == null) { continue; } propName = dest.Destination.Trim(); } // get the value object value = prop.GetValue(obj); // any null values just set to DB Null if (value == null) { param = new SQLiteParameter($":{propName}", Convert.DBNull); } // strings else if (prop.PropertyType == typeof(string)) { param = new SQLiteParameter($":{propName}", (value as string)); } // Guids else if (prop.PropertyType == typeof(Guid) || prop.PropertyType == typeof(Nullable <Guid>)) { param = new SQLiteParameter($":{propName}", ((Guid)value).ToString()); } // dates of any kind else if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(Nullable <DateTime>)) { param = new SQLiteParameter($":{propName}", value); } else if (prop.PropertyType == typeof(DateTimeOffset) || prop.PropertyType == typeof(Nullable <DateTimeOffset>)) { param = new SQLiteParameter($":{propName}", value); } // bools are converted to int else if (prop.PropertyType == typeof(bool) || prop.PropertyType == typeof(Nullable <bool>)) { param = new SQLiteParameter($":{propName}", (bool)value ? 1 : 0); } // enums are int until we create an attribute option to specify text else if (prop.PropertyType.IsEnum) { param = new SQLiteParameter($":{propName}", (int)value); } // binary blobs else if (prop.PropertyType == typeof(byte[])) { param = new SQLiteParameter($":{propName}", value); } else if (!prop.PropertyType.IsClass) // everything else thats NOT a class we have not already handled { param = new SQLiteParameter($":{propName}", value); } // add the whole thing to the dictionary if (param != null) { paras.Add(propName, param); } } // roll the query var parameters = paras.Select(n => n.Value.ParameterName).ToArray(); string query = $"INSERT INTO {tableName} ({String.Join( ",", paras.Keys.ToArray() )}) VALUES ({String.Join( ",", parameters)})"; SQLiteCommand cmd = new SQLiteCommand(query); cmd.CommandType = System.Data.CommandType.Text; cmd.Parameters.AddRange(paras.Values.ToArray()); return(cmd); }