public virtual void CopyAttributes(SQLiteColumnAttribute attribute) { if (attribute == null) { throw new ArgumentNullException(nameof(attribute)); } IsReadOnly = attribute.IsReadOnly; IsNullable = attribute.IsNullable; IsPrimaryKey = attribute.IsPrimaryKey; InsertOnly = attribute.InsertOnly; UpdateOnly = attribute.UpdateOnly; AutoIncrements = attribute.AutoIncrements; AutomaticType = attribute.AutomaticType; HasDefaultValue = attribute.HasDefaultValue; Collation = attribute.Collation; BindOptions = attribute.BindOptions; PrimaryKeyDirection = attribute.PrimaryKeyDirection; IsUnique = attribute.IsUnique; CheckExpression = attribute.CheckExpression; if (HasDefaultValue) { if (!Table.Database.TryChangeType(attribute.DefaultValue, ClrType, out object value)) { string type = attribute.DefaultValue != null ? "'" + attribute.DefaultValue.GetType().FullName + "'" : "<null>"; throw new SqlNadoException("0023: Cannot convert attribute DefaultValue `" + attribute.DefaultValue + "` of type " + type + " for column '" + Name + "' of table '" + Table.Name + "'."); } DefaultValue = value; IsDefaultValueIntrinsic = attribute.IsDefaultValueIntrinsic; } }
protected virtual SQLiteColumnAttribute AddAnnotationAttributes(PropertyInfo property, SQLiteColumnAttribute attribute) { if (property == null) { throw new ArgumentNullException(nameof(property)); } // NOTE: we don't add RequiredAttribute, ColumnAttribute here because that would require us to add a package // but check the test project, it has an example in the TestDataAnnotations method. return(attribute); }
protected virtual void AddIndices(SQLiteObjectTable table, IDictionary <string, IReadOnlyList <Tuple <SQLiteColumnAttribute, SQLiteIndexAttribute> > > indices) { if (table == null) { throw new ArgumentNullException(nameof(table)); } if (indices == null) { throw new ArgumentNullException(nameof(indices)); } foreach (var index in indices) { var list = index.Value; for (int i = 0; i < list.Count; i++) { SQLiteColumnAttribute col = list[i].Item1; SQLiteIndexAttribute idx = list[i].Item2; if (idx.Order == SQLiteIndexAttribute.DefaultOrder) { idx.Order = i; } } var columns = new List <SQLiteIndexedColumn>(); bool unique = false; string schemaName = null; foreach (var kv in list.OrderBy(l => l.Item2.Order)) { var col = CreateIndexedColumn(kv.Item1.Name); if (col == null) { throw new InvalidOperationException(); } col.CollationName = kv.Item2.CollationName; col.Direction = kv.Item2.Direction; // if at least one defines unique, it's unique if (kv.Item2.IsUnique) { unique = true; } // first schema defined is used if (!string.IsNullOrWhiteSpace(kv.Item2.SchemaName)) { schemaName = kv.Item2.SchemaName; } columns.Add(col); } var oidx = CreateObjectIndex(table, index.Key, columns); if (oidx == null) { throw new InvalidOperationException(); } oidx.IsUnique = unique; oidx.SchemaName = schemaName; table.AddIndex(oidx); } }
protected virtual SQLiteColumnAttribute GetColumnAttribute(PropertyInfo property) { if (property == null) { throw new ArgumentNullException(nameof(property)); } // discard enumerated types unless att is defined to not ignore var att = property.GetCustomAttribute <SQLiteColumnAttribute>(); if (property.PropertyType != typeof(string)) { var et = Conversions.GetEnumeratedType(property.PropertyType); if (et != null) { if (et != typeof(byte)) { if (att == null || !att._ignore.HasValue || att._ignore.Value) { return(null); } } } } if (att != null && att.Ignore) { return(null); } if (att == null) { att = new SQLiteColumnAttribute(); } if (att.ClrType == null) { att.ClrType = property.PropertyType; } if (string.IsNullOrWhiteSpace(att.Name)) { att.Name = property.Name; } if (string.IsNullOrWhiteSpace(att.Collation)) { att.Collation = Database.DefaultColumnCollation; } if (string.IsNullOrWhiteSpace(att.DataType)) { if (typeof(ISQLiteBlobObject).IsAssignableFrom(att.ClrType)) { att.DataType = SQLiteColumnType.BLOB.ToString(); } else { if (att.HasDefaultValue && att.IsDefaultValueIntrinsic && att.DefaultValue is string df) { // https://www.sqlite.org/lang_createtable.html if (IsComputedDefaultValue(df)) { att.DataType = SQLiteColumnType.TEXT.ToString(); // we need to force this column type options att.BindOptions = att.BindOptions ?? Database.CreateBindOptions(); att.BindOptions.DateTimeFormat = SQLiteDateTimeFormat.SQLiteIso8601; } } } if (string.IsNullOrWhiteSpace(att.DataType)) { att.DataType = GetDefaultDataType(att.ClrType); } } if (!att._isNullable.HasValue) { att.IsNullable = att.ClrType.IsNullable() || !att.ClrType.IsValueType; } if (!att._isReadOnly.HasValue) { att.IsReadOnly = !property.CanWrite; } if (att.GetValueExpression == null) { // equivalent of // att.GetValueFunc = (o) => property.GetValue(o); var instanceParameter = Expression.Parameter(typeof(object)); var instance = Expression.Convert(instanceParameter, property.DeclaringType); Expression getValue = Expression.Property(instance, property); if (att.ClrType != typeof(object)) { getValue = Expression.Convert(getValue, typeof(object)); } var lambda = Expression.Lambda <Func <object, object> >(getValue, instanceParameter); att.GetValueExpression = lambda; } if (!att.IsReadOnly && att.SetValueExpression == null && property.SetMethod != null) { // equivalent of // att.SetValueAction = (options, o, v) => { // if (options.TryChangeType(v, typeof(property), options.FormatProvider, out object newv)) // { // property.SetValue(o, newv); // } // } var optionsParameter = Expression.Parameter(typeof(SQLiteLoadOptions), "options"); var instanceParameter = Expression.Parameter(typeof(object), "instance"); var valueParameter = Expression.Parameter(typeof(object), "value"); var instance = Expression.Convert(instanceParameter, property.DeclaringType); var expressions = new List <Expression>(); var variables = new List <ParameterExpression>(); Expression setValue; if (att.ClrType != typeof(object)) { var convertedValue = Expression.Variable(typeof(object), "cvalue"); variables.Add(convertedValue); var tryConvert = Expression.Call( optionsParameter, typeof(SQLiteLoadOptions).GetMethod(nameof(SQLiteLoadOptions.TryChangeType), new Type[] { typeof(object), typeof(Type), typeof(object).MakeByRefType() }), valueParameter, Expression.Constant(att.ClrType, typeof(Type)), convertedValue); var ifTrue = Expression.Call(instance, property.SetMethod, Expression.Convert(convertedValue, att.ClrType)); var ifFalse = Expression.Empty(); setValue = Expression.Condition(Expression.Equal(tryConvert, Expression.Constant(true)), ifTrue, ifFalse); } else { setValue = Expression.Call(instance, property.SetMethod, valueParameter); } expressions.Add(setValue); var body = Expression.Block(variables, expressions); var lambda = Expression.Lambda <Action <SQLiteLoadOptions, object, object> >(body, optionsParameter, instanceParameter, valueParameter); att.SetValueExpression = lambda; } return(att); }