private void AnalyzeFields() { IList relations = new ArrayList(); var fis = this.classType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(fi => !fi.IsInitOnly); foreach (FieldInfo fi in fis) { string fname = fi.Name; if (fname.StartsWith("_ndo")) { continue; } if (fi.FieldType.IsSubclassOf(typeof(System.Delegate))) { continue; } object[] attributes = fi.GetCustomAttributes(false); bool cont = false; foreach (System.Attribute attr in attributes) { if (attr is NDOTransientAttribute) { cont = true; break; } if (attr is NDORelationAttribute) { this.relations.Add(new RelationNode(fi, (NDORelationAttribute)attr, this)); cont = true; break; } } if (cont) { continue; } // Field type is persistent - assume relation with element multiplicity. if (typeof(IPersistenceCapable).IsAssignableFrom(fi.FieldType)) { NDORelationAttribute nra = new NDORelationAttribute(fi.FieldType, RelationInfo.Default); this.relations.Add(new RelationNode(fi, nra, this)); continue; } // Field is a collection - assume that it is either a relation or a transient field. if (GenericIListReflector.IsGenericIList(fi.FieldType)) { if (typeof(IPersistenceCapable).IsAssignableFrom(fi.FieldType.GetGenericArguments()[0])) { NDORelationAttribute nra = new NDORelationAttribute(fi.FieldType.GetGenericArguments()[0], RelationInfo.Default); this.relations.Add(new RelationNode(fi, nra, this)); } else { Console.WriteLine("Warning: The field " + this.name + "." + fi.Name + " is a generic collection to a nonpersistent type. NDO assumes, that this field is transient."); } continue; } if (!fi.FieldType.IsGenericParameter && fi.FieldType.IsClass && fi.FieldType != typeof(string) && fi.FieldType != typeof(byte[])) { this.embeddedTypes.Add(new EmbeddedTypeNode(fi)); } else { FieldNode fn = new FieldNode(fi); this.fields.Add(fn); Type ft = fi.FieldType; if (ft.IsValueType && !ft.IsEnum && !StorableTypes.Contains(ft)) { ValueTypes.Instance.Add(new ValueTypeNode(ft)); } } } // If there is more than one relation to the same target type // without relation name, assign a relation name automatically foreach (var group in this.relations.GroupBy(r => r.RelatedType)) { if (group.Count() < 2) { continue; } int countWithoutName = 0; foreach (var rel in group) { if (string.IsNullOrEmpty(rel.RelationName)) { if (countWithoutName > 0) { string relname = rel.Name; if (relname[0] == '<') { int q = relname.IndexOf('>'); if (q == -1) { q = relname.Length; } relname = relname.Substring(1, q - 1); } rel.RelationName = relname; } countWithoutName++; } } } }
public RelationNode(FieldInfo relationFieldInfo, NDORelationAttribute attr, ClassNode parent) { this.parent = parent; this.fieldType = relationFieldInfo.FieldType; Type parentType = relationFieldInfo.ReflectedType; NDOAssemblyName an = new NDOAssemblyName(parentType.Assembly.FullName); string assShortName = an.Name; this.isElement = !(relationFieldInfo.FieldType == typeof(IList) || relationFieldInfo.FieldType.GetInterface("IList") != null || GenericIListReflector.IsGenericIList(relationFieldInfo.FieldType)); // dataType & declaringType always have // - a class/valutype prefix // - an [AssName] prefix this.dataType = new ReflectedType(relationFieldInfo.FieldType).ILName; if (relationFieldInfo.DeclaringType != relationFieldInfo.ReflectedType) { this.declaringType = new ReflectedType(relationFieldInfo.DeclaringType).ILName; } else { this.declaringType = null; } this.name = relationFieldInfo.Name; Type attrType = attr.GetType(); this.relationName = attr.RelationName; this.relationInfo = attr.Info; Type relType; if (isElement) { relType = relationFieldInfo.FieldType; } else { if (attr.RelationType == null && relationFieldInfo.FieldType.IsGenericType) { relType = relationFieldInfo.FieldType.GetGenericArguments()[0]; } else { relType = attr.RelationType; } if (relType == null) { throw new Exception("Can't determine referenced type in relation " + parent.Name + "." + this.name + ". Provide a type parameter for the [NDORelation] attribute."); } } if (relType.IsGenericType && !relType.IsGenericTypeDefinition) { relType = relType.GetGenericTypeDefinition(); } // Related Type hat kein "class " Prefix, hat [assName] nur bei fremden Assemblies. this.relatedType = new ReflectedType(relType, assShortName).ILNameWithoutPrefix; if (relType.IsGenericType) { this.relatedType = this.relatedType.Substring(0, this.relatedType.IndexOf('<')); } object[] attrs = relationFieldInfo.GetCustomAttributes(typeof(ForeignKeyColumnAttribute), true); if (attrs.Length > 0) { this.foreignKeyColumnAttributes = new ForeignKeyColumnAttribute[attrs.Length]; attrs.CopyTo(this.foreignKeyColumnAttributes, 0); } attrs = relationFieldInfo.GetCustomAttributes(typeof(ChildForeignKeyColumnAttribute), true); if (attrs.Length > 0) { this.childForeignKeyColumnAttributes = new ChildForeignKeyColumnAttribute[attrs.Length]; attrs.CopyTo(this.childForeignKeyColumnAttributes, 0); } attrs = relationFieldInfo.GetCustomAttributes(typeof(MappingTableAttribute), true); if (attrs.Length > 0) { MappingTableAttribute = (MappingTableAttribute)attrs[0]; } }
void IFieldInitializer.InitFields() { bool isEnhancing = ((IEnhancerSupport)Parent.Parent).IsEnhancing; if (!isEnhancing) { GetOrdinal(); } Class relatedClass = this.RelatedClass; Type t = Parent.SystemType; if (t == null) { throw new InternalException(1155, "Relation.InitFields"); } FieldInfo fi = null; while (fi == null && t != typeof(object)) { fi = t.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); if (fi == null) { t = t.BaseType; } } if (fi == null) { throw new NDOException(20, "Can't find field " + Parent.SystemType.Name + "." + FieldName); } FieldType = fi.FieldType; System.Attribute a = System.Attribute.GetCustomAttribute(fi, typeof(NDORelationAttribute), false); NDORelationAttribute ra = (NDORelationAttribute)a; this.composition = ra != null && (ra.Info & RelationInfo.Composite) != 0; if (fi.FieldType == typeof(System.Collections.IList) || fi.FieldType.GetInterface("IList") != null || fi.FieldType.FullName.StartsWith("System.Collections.Generic.IList`1")) { this.multiplicity = RelationMultiplicity.List; } else if (fi.FieldType.GetCustomAttributes(typeof(NDOPersistentAttribute), false).Length > 0) { this.multiplicity = RelationMultiplicity.Element; } else { throw new NDOException(111, "Invalid field type for relation " + t.FullName + "." + FieldName + ": Type = " + fi.FieldType.Name); } // This could be easier, if we hadn't the choice whether to use // polymorphy or not. bool cond1 = this.Multiplicity == RelationMultiplicity.Element && this.ForeignKeyTypeColumnName != null; bool cond2 = this.Multiplicity == RelationMultiplicity.List && this.MappingTable != null && this.MappingTable.ChildForeignKeyTypeColumnName != null; hasSubclasses = (relatedClass.HasSubclasses) && (cond1 || cond2); if (this.multiplicity == RelationMultiplicity.List) { if (ra == null) { throw new NDOException(97, $"Can't determine relation type for relation {Parent.FullName}.{fi.Name}"); } if (ra.RelationType == null && fi.FieldType.IsGenericType) { this.referencedType = fi.FieldType.GetGenericArguments()[0]; } else { this.referencedType = ra.RelationType; } if (referencedType == null) { throw new NDOException(101, "Can't determine referenced type in relation " + this.Parent.FullName + "." + this.fieldName + ". Provide a type parameter for the [NDORelation] attribute."); } } else { this.referencedType = FieldType; } if (HasSubclasses && Multiplicity == RelationMultiplicity.List && MappingTable == null) { //throw new NDOException(21, "Polymorphic 1:n-relation w/o mapping table is not supported"); Debug.WriteLine("NDO Warning: Polymorphic 1:n-relation " + Parent.FullName + "." + this.FieldName + " w/o mapping table"); } this.definingClass = this.Parent; Type bt = this.Parent.SystemType.BaseType; while (typeof(IPersistenceCapable).IsAssignableFrom(bt)) { Class pcl = this.Parent.Parent.FindClass(bt); if (pcl.FindRelation(this.fieldName) != null) { this.definingClass = pcl; } else { break; } bt = bt.BaseType; } // Do not set fkColumn.Size to a value != 0 in during enhancing, // because that value would be hard coded into the mapping file. // Use (!isEnhancing) to make sure, that the code wasn't called from the enhancer. if (this.MappingTable != null) { // r.ForeignKeyColumns points to the own table. if (Parent.Oid.OidColumns.Count != this.foreignKeyColumns.Count) { throw new NDOException(115, "Column count between relation and Oid doesn't match. Type " + Parent.FullName + " has an oid column count of " + Parent.Oid.OidColumns.Count + ". The Relation " + Parent.FullName + "." + this.fieldName + " has a foreign key column count of " + this.foreignKeyColumns.Count + '.'); } int i = 0; new ForeignKeyIterator(this).Iterate(delegate(ForeignKeyColumn fkColumn, bool isLastIndex) { OidColumn oidColumn = (OidColumn)Parent.Oid.OidColumns[i]; if (!isEnhancing && fkColumn.Size == 0) { fkColumn.Size = oidColumn.Size; } fkColumn.SystemType = oidColumn.SystemType; i++; } ); // r.MappingTable.ChildForeignKeyColumns points to the table of the related class. if (relatedClass.Oid.OidColumns.Count != this.mappingTable.ChildForeignKeyColumns.Count()) { throw new NDOException(115, "Column count between relation and Oid doesn't match. Type " + relatedClass.FullName + " has an oid column count of " + relatedClass.Oid.OidColumns.Count + ". The Relation " + this.Parent.FullName + "." + this.fieldName + " has a foreign key column count of " + this.mappingTable.ChildForeignKeyColumns.Count() + '.'); } i = 0; new ForeignKeyIterator(this.mappingTable).Iterate(delegate(ForeignKeyColumn fkColumn, bool isLastIndex) { OidColumn oidColumn = (OidColumn)relatedClass.Oid.OidColumns[i]; if (!isEnhancing && fkColumn.Size == 0) { fkColumn.Size = oidColumn.Size; } fkColumn.SystemType = oidColumn.SystemType; i++; } ); } else if (this.multiplicity == RelationMultiplicity.Element) // The foreign key points to the tabel of the related class. { if (relatedClass.Oid.OidColumns.Count != this.foreignKeyColumns.Count) { throw new NDOException(115, "Column count between relation and Oid doesn't match. Type " + relatedClass.FullName + " has an oid column count of " + relatedClass.Oid.OidColumns.Count + ". The Relation " + Parent.FullName + "." + this.fieldName + " has a foreign key column count of " + this.foreignKeyColumns.Count + '.'); } int i = 0; new ForeignKeyIterator(this).Iterate(delegate(ForeignKeyColumn fkColumn, bool isLastIndex) { OidColumn oidColumn = (OidColumn)relatedClass.Oid.OidColumns[i]; if (!isEnhancing && fkColumn.Size == 0) { fkColumn.Size = oidColumn.Size; } fkColumn.SystemType = oidColumn.SystemType; i++; } ); } else // List relation. The foreign key points to the own table. { if (Parent.Oid.OidColumns.Count != this.foreignKeyColumns.Count) { throw new NDOException(115, "Column count between relation and Oid doesn't match. Type " + Parent.FullName + " has an oid column count of " + Parent.Oid.OidColumns.Count + ". The Relation " + Parent.FullName + "." + this.fieldName + " has a foreign key column count of " + this.foreignKeyColumns.Count + '.'); } int i = 0; new ForeignKeyIterator(this).Iterate(delegate(ForeignKeyColumn fkColumn, bool isLastIndex) { OidColumn oidColumn = (OidColumn)Parent.Oid.OidColumns[i]; if (!isEnhancing && fkColumn.Size == 0) { fkColumn.Size = oidColumn.Size; } fkColumn.SystemType = oidColumn.SystemType; i++; } ); } }