public CodeFirst() { _tables = new Dictionary <string, Table>(); var baseType = typeof(JsonObject); var assembly = baseType.Assembly; _foreignKeys = new Dictionary <Field, ForeignKeyAttribute>(); foreach (Type tbl in assembly.GetTypes().Where(t => t.BaseType == baseType)) { if (!tbl.IsDefined(typeof(TableAttribute))) { continue; } processTable(tbl, null); } foreach (Field fld in _foreignKeys.Keys) { ForeignKeyAttribute fk = _foreignKeys[fld]; Table tbl = TableFor(fk.Table); fld.ForeignKey = new ForeignKey(tbl, tbl.Fields[0]); } foreach (Type tbl in assembly.GetTypes().Where(t => t.IsSubclassOf(baseType))) { ViewAttribute view = tbl.GetCustomAttribute <ViewAttribute>(); if (view == null) { continue; } processTable(tbl, view); } _foreignKeys = null; }
void processFields(Type tbl, ref List <Field> fields, ref Dictionary <string, List <Tuple <int, Field> > > indexes, ref List <Tuple <int, Field> > primary, ref string primaryName) { if (tbl.BaseType != typeof(JsonObject)) // Process base types first { processFields(tbl.BaseType, ref fields, ref indexes, ref primary, ref primaryName); } foreach (FieldInfo field in tbl.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) { if (field.IsDefined(typeof(DoNotStoreAttribute))) { continue; } bool nullable = field.IsDefined(typeof(NullableAttribute)); Type pt = field.FieldType; decimal length = 0; string defaultValue = null; // Convert nullable types to their base type, but set nullable flag if (pt == typeof(bool?)) { pt = typeof(bool); nullable = true; } else if (pt == typeof(int?)) { pt = typeof(int); nullable = true; } else if (pt == typeof(decimal?)) { pt = typeof(decimal); nullable = true; } else if (pt == typeof(double?)) { pt = typeof(double); nullable = true; } else if (pt == typeof(DateTime?)) { pt = typeof(DateTime); nullable = true; } PrimaryAttribute pk = field.GetCustomAttribute <PrimaryAttribute>(); if (pk != null) { nullable = false; // Primary keys may not be null } // Set length and default value (may be overridden later by specific attributes) if (pt == typeof(bool)) { length = 1; defaultValue = "0"; } else if (pt == typeof(int)) { length = 11; defaultValue = "0"; } else if (pt == typeof(decimal)) { length = 10.2M; defaultValue = "0.00"; } else if (pt == typeof(double)) { length = 10.4M; defaultValue = "0"; } else if (pt == typeof(string)) { length = 45; defaultValue = ""; } if (nullable) { defaultValue = null; // If field is nullable, null is always the default value } LengthAttribute la = field.GetCustomAttribute <LengthAttribute>(); if (la != null) // Override length { length = la.Length + la.Precision / 10M; } DefaultValueAttribute da = field.GetCustomAttribute <DefaultValueAttribute>(); if (da != null) // Override default value { defaultValue = da.Value; } Field fld = new Field(field.Name, pt, length, nullable, pk != null && pk.AutoIncrement, defaultValue); if (pk != null) { primary.Add(new Tuple <int, Field>(pk.Sequence, fld)); Utils.Check(primaryName == null || primaryName == pk.Name, "2 Primary keys defined on {0}", tbl.Name); primaryName = pk.Name; } // See if the field is in one or more indexes foreach (UniqueAttribute a in field.GetCustomAttributes <UniqueAttribute>()) { List <Tuple <int, Field> > index; if (!indexes.TryGetValue(a.Name, out index)) { // New index index = new List <Tuple <int, Field> >(); indexes[a.Name] = index; } // Add field to index index.Add(new Tuple <int, Field>(a.Sequence, fld)); } // See if the field is a foreign key ForeignKeyAttribute fk = field.GetCustomAttribute <ForeignKeyAttribute>(); if (fk != null) { _foreignKeys[fld] = fk; } fields.Add(fld); } }