//public void SetData(IEnumerable<string> fieldsToSet, Dictionary<string, Tuple<ISelectQuery, Dictionary<string, string>>> queries, DataRow row) //{ // if (!IsEditable) // { // throw new ReadOnlyException("Cannot call SetData on a read-only Data Object"); // } // SchemaObject schemaObject = Schema.Schema.GetSchemaObject(GetType()); // foreach (IGrouping<string, string> fieldByPath in fieldsToSet.GroupBy(field => // { // if (field.Contains(".")) // { // return field.Substring(0, field.LastIndexOf('.')); // } // return string.Empty; // })) // { // DataObject objectToSetValueOn = this; // if (fieldByPath.Key.Contains(".")) // { // string[] parts = fieldByPath.Key.Split('.'); // SchemaObject lastSchemaObject = schemaObject; // for (int i = 0; i < parts.Length - 1; i++) // { // Relationship relationship = lastSchemaObject.GetRelationship(parts[i]); // if (relationship != null) // { // DataObject relatedDataObject = relationship.GetValue(objectToSetValueOn); // if (relatedDataObject == null) // { // relatedDataObject = (DataObject)Activator.CreateInstance(relationship.RelatedObjectType); // relationship.SetPrivateDataCallback(objectToSetValueOn, relatedDataObject); // } // objectToSetValueOn = relatedDataObject; // lastSchemaObject = relationship.RelatedSchemaObject; // } // else if (lastSchemaObject.GetRelationshipList(parts[i]) != null) // { // break; // } // } // } // string fieldAlias = tableAliasesByFieldPath[fieldByPath.Key]; // foreach (string field in fieldByPath) // { // string fieldName = field; // if (fieldName.Contains('.')) // { // fieldName = fieldName.Substring(fieldName.LastIndexOf('.') + 1); // } // string columnName = $"{fieldAlias}_{fieldName}"; // object databaseValue = row[columnName]; // databaseValue = databaseValue == DBNull.Value ? null : databaseValue; // Schema.Field schemaField = schemaObject.GetField(field); // schemaField.SetPrivateDataCallback(objectToSetValueOn, databaseValue); // } // } //} public void SetData(IEnumerable <string> fieldsToSet, Dictionary <string, Tuple <ISelectQuery, Dictionary <string, string> > > queries, DataRow outerObjectRow) { IEnumerable <string> fieldsWeCanDoSomethingAbout = fieldsToSet.Where(field => !queries.Keys.Where(k => !string.IsNullOrEmpty(k)).Any(reverseFieldPath => field.StartsWith(reverseFieldPath))); IEnumerable <IGrouping <string, string> > fieldsByFieldPath = fieldsWeCanDoSomethingAbout.OrderBy(field => field).GroupBy(field => field.Contains('.') ? field.Substring(0, field.LastIndexOf('.')) : ""); // Load in all parent relationships foreach (IGrouping <string, string> fieldGroup in fieldsByFieldPath.Where(group => !string.IsNullOrEmpty(group.Key))) { SchemaObject currentSchemaObject = Schema.Schema.GetSchemaObject(GetType()); DataObject currentObject = this; string[] fieldPathParts = fieldGroup.Key.Split('.'); for (int i = 0; i < fieldPathParts.Length; i++) { Relationship relationship = currentSchemaObject.GetRelationship(fieldPathParts[i]); DataObject relatedObject = relationship.GetValue(this); if (relatedObject == null) { relatedObject = (DataObject)Activator.CreateInstance(relationship.RelatedObjectType); relatedObject.isEditable = false; relationship.SetPrivateDataCallback(currentObject, relatedObject); } currentSchemaObject = relationship.RelatedSchemaObject; currentObject = relatedObject; } } Dictionary <string, string> tableAliasesForOuterRow = queries[""].Item2; // Set data on this object or parent objects foreach (IGrouping <string, string> fieldGroup in fieldsByFieldPath) { string tableAlias = tableAliasesForOuterRow[fieldGroup.Key]; DataObject dataObjectToSet = this; SchemaObject schemaObjectToSet = Schema.Schema.GetSchemaObject(GetType()); if (!string.IsNullOrEmpty(fieldGroup.Key)) { string[] fieldPathParts = fieldGroup.Key.Split('.'); for (int i = 0; i < fieldPathParts.Length; i++) { Relationship relationship = schemaObjectToSet.GetRelationship(fieldPathParts[i]); dataObjectToSet = relationship.GetValue(dataObjectToSet); schemaObjectToSet = Schema.Schema.GetSchemaObject(dataObjectToSet.GetType()); } } foreach (string field in fieldGroup) { string fieldToSet = field; if (fieldToSet.Contains('.')) { fieldToSet = fieldToSet.Substring(fieldToSet.LastIndexOf('.') + 1); } object value = outerObjectRow[$"{tableAlias}_{fieldToSet}"]; Schema.Field schemaField = schemaObjectToSet.GetField(fieldToSet); schemaField.SetPrivateDataCallback(dataObjectToSet, value); } } // Set data for reverse relationships HashSet <string> handledReverseRelationships = new HashSet <string>(); foreach (string reverseRelationship in queries.Keys.Where(key => !string.IsNullOrEmpty(key))) { string[] reverseRelationshipParts = reverseRelationship.Split('.'); DataObject parentObject = this; SchemaObject parentSchemaObject = Schema.Schema.GetSchemaObject(GetType()); string reverseRelationshipWeCanDoSomethingAbout = ""; RelationshipList relationshipList = null; for (int i = 0; i < reverseRelationshipParts.Length; i++) { Relationship relationship = parentSchemaObject.GetRelationship(reverseRelationshipParts[i]); if (relationship != null) { parentObject = relationship.GetValue(parentObject); parentSchemaObject = relationship.RelatedSchemaObject; reverseRelationshipWeCanDoSomethingAbout += relationship.RelatedSchemaObject.ObjectName + "."; } else { relationshipList = parentSchemaObject.GetRelationshipList(reverseRelationshipParts[i]); reverseRelationshipWeCanDoSomethingAbout += relationshipList.RelationshipListName + "."; break; } } if (!handledReverseRelationships.Add(reverseRelationshipWeCanDoSomethingAbout)) { continue; } long? primaryKey = parentObject.PrimaryKeyField.GetValue(parentObject) as long?; ISelectQuery query = queries[reverseRelationshipWeCanDoSomethingAbout].Item1; Condition primaryKeyCondition = new Condition() { Left = (Base.Data.Operand.Field)relationshipList.ForeignKeyName, ConditionType = Condition.ConditionTypes.Equal, Right = new Literal(primaryKey) }; ICondition previousQueryCondition = query.WhereCondition; if (query.WhereCondition != null) { ConditionGroup conditionGroup = new ConditionGroup() { ConditionGroupType = ConditionGroup.ConditionGroupTypes.And, Conditions = new List <ICondition>() { query.WhereCondition, primaryKeyCondition } }; query.WhereCondition = conditionGroup; } else { query.WhereCondition = primaryKeyCondition; } HashSet <string> childFieldsToSet = fieldsToSet.Where(f => f.StartsWith(reverseRelationshipWeCanDoSomethingAbout)).Select(f => f.Replace(reverseRelationshipWeCanDoSomethingAbout, "")).ToHashSet(); childFieldsToSet.Add(relationshipList.RelatedSchemaObject.PrimaryKeyField.FieldName); Dictionary <string, Tuple <ISelectQuery, Dictionary <string, string> > > childQueries = new Dictionary <string, Tuple <ISelectQuery, Dictionary <string, string> > >(); foreach (KeyValuePair <string, Tuple <ISelectQuery, Dictionary <string, string> > > childQuery in queries.Where(kvp => kvp.Key.StartsWith(reverseRelationshipWeCanDoSomethingAbout))) { childQueries.Add(childQuery.Key.Replace(reverseRelationshipWeCanDoSomethingAbout, ""), childQuery.Value); } object reverseRelationshipList = relationshipList.GetPrivateDataCallback(parentObject); MethodInfo addMethod = reverseRelationshipList.GetType().GetMethod("Add", new Type[] { relationshipList.RelatedObjectType }); DataTable results = query.Execute(null); query.WhereCondition = previousQueryCondition; foreach (DataRow row in results.Rows) { DataObject childObject = (DataObject)Activator.CreateInstance(relationshipList.RelatedObjectType); childObject.isEditable = false; childObject.SetData(childFieldsToSet, childQueries, row); addMethod.Invoke(reverseRelationshipList, new object[] { childObject }); } parentObject.retrievedPaths.Add(relationshipList.RelationshipListName); } }
private Dictionary <string, Tuple <ISelectQuery, Dictionary <string, string> > > GetBaseQueries(SchemaObject thisSchemaObject, HashSet <string> fields, string upperFieldPath = null) { Dictionary <string, Tuple <ISelectQuery, Dictionary <string, string> > > queriesByFieldPath = new Dictionary <string, Tuple <ISelectQuery, Dictionary <string, string> > >(); DataObject dataObject = (DataObject)Activator.CreateInstance(thisSchemaObject.DataObjectType); fields.Add(thisSchemaObject.PrimaryKeyField.FieldName); IEnumerable <string> sortedFields = fields.Where(f => !f.Contains(".")).Concat(fields.Where(f => f.Contains(".")).OrderBy(str => str)); Dictionary <string, string> tableAliasesByFieldPath = new Dictionary <string, string>() { { "", "table000" } }; int tableAliasCounter = 1; List <Join> joinList = new List <Join>(); foreach (string fieldPath in sortedFields.Where(f => f.Contains(".")).Select(f => f.Substring(0, f.LastIndexOf(".")))) { string[] fieldPathParts = fieldPath.Split('.'); string checkedFieldPath = ""; DataObject lastObject = dataObject; SchemaObject lastSchemaObject = thisSchemaObject; for (int i = 0; i < fieldPathParts.Length; i++) { string myAlias = tableAliasesByFieldPath[checkedFieldPath]; if (!string.IsNullOrEmpty(checkedFieldPath)) { checkedFieldPath += "."; } checkedFieldPath += fieldPathParts[i]; RelationshipList relationshipList = lastSchemaObject.GetRelationshipList(fieldPathParts[i]); if (relationshipList != null) { if (queriesByFieldPath.ContainsKey(checkedFieldPath + ".")) { break; } HashSet <string> fieldsAfterReverseRelationship = sortedFields.Where(field => field.StartsWith(checkedFieldPath + ".")).Select(f => f.Replace(checkedFieldPath + ".", "")).ToHashSet(); fieldsAfterReverseRelationship.Add(relationshipList.RelatedSchemaObject.PrimaryKeyField.FieldName); foreach (KeyValuePair <string, Tuple <ISelectQuery, Dictionary <string, string> > > kvp in GetBaseQueries(relationshipList.RelatedSchemaObject, fieldsAfterReverseRelationship, (upperFieldPath ?? "") + checkedFieldPath + ".")) { queriesByFieldPath.Add(checkedFieldPath + "." + kvp.Key, kvp.Value); } break; } Relationship relationship = lastSchemaObject.GetRelationship(fieldPathParts[i]); SchemaObject relatedSchemaObject = relationship.RelatedSchemaObject; DataObject relatedDataObject = (DataObject)Activator.CreateInstance(relatedSchemaObject.DataObjectType); if (tableAliasesByFieldPath.ContainsKey(checkedFieldPath)) { lastObject = relatedDataObject; lastSchemaObject = relatedSchemaObject; continue; } fields.Add(checkedFieldPath + "." + relatedSchemaObject.PrimaryKeyField.FieldName); tableAliasCounter++; string otherAlias = $"table{tableAliasCounter.ToString("D3")}"; tableAliasesByFieldPath.Add(checkedFieldPath, otherAlias); Join join = new Join(); join.Table = new Table(relatedSchemaObject.SchemaName, relatedSchemaObject.ObjectName, otherAlias); join.JoinType = Join.JoinTypes.Left; join.Condition = lastObject.GetRelationshipCondition(relationship, myAlias, otherAlias); joinList.Add(join); lastObject = relatedDataObject; lastSchemaObject = relatedSchemaObject; } } if (SearchCondition != null) { foreach (string conditionFieldPath in SearchCondition.GetFieldPaths()) { if (string.IsNullOrEmpty(conditionFieldPath)) { continue; } string workingConditionFieldPath = conditionFieldPath + "."; if (!string.IsNullOrEmpty(upperFieldPath)) { if (!workingConditionFieldPath.StartsWith(upperFieldPath)) { continue; } workingConditionFieldPath = workingConditionFieldPath.Replace(upperFieldPath, ""); } if (tableAliasesByFieldPath.ContainsKey(workingConditionFieldPath)) { continue; } string[] parts = workingConditionFieldPath.Split('.'); DataObject lastObject = dataObject; SchemaObject lastSchemaObject = thisSchemaObject; string workingPath = ""; foreach (string part in parts) { if (string.IsNullOrEmpty(part)) { continue; } string myAlias = tableAliasesByFieldPath[workingPath]; if (!string.IsNullOrEmpty(workingPath)) { workingPath += "."; } workingPath += part; RelationshipList relationshipList = lastSchemaObject.GetRelationshipList(part); if (relationshipList != null) { break; // This will happen later } Relationship relationship = lastSchemaObject.GetRelationship(part); DataObject relatedObject = relationship.GetValue(lastObject); if (relatedObject == null) { relatedObject = (DataObject)Activator.CreateInstance(relationship.RelatedObjectType); } lastSchemaObject = relationship.RelatedSchemaObject; if (tableAliasesByFieldPath.ContainsKey(workingPath)) { lastObject = relatedObject; continue; } string newAlias = $"table{tableAliasCounter.ToString("D3")}"; tableAliasCounter++; Join join = new Join(); join.JoinType = Join.JoinTypes.Left; join.Table = new Table(lastSchemaObject.SchemaName, lastSchemaObject.ObjectName, newAlias); join.Condition = lastObject.GetRelationshipCondition(relationship, myAlias, newAlias); joinList.Add(join); lastObject = relatedObject; tableAliasesByFieldPath[workingPath] = newAlias; } } } ISelectQuery selectQuery = SQLProviderFactory.GetSelectQuery(); selectQuery.Table = new Table(thisSchemaObject.SchemaName, thisSchemaObject.ObjectName, "table000"); selectQuery.JoinList = joinList; foreach (string field in sortedFields.Where(f => !queriesByFieldPath.Keys.Any(fp => f.StartsWith(fp)))) { string path = ""; string fieldName = ""; if (field.Contains('.')) { path = field.Substring(0, field.LastIndexOf('.')); fieldName = field.Substring(field.LastIndexOf('.') + 1); } else { fieldName = field; } string alias = tableAliasesByFieldPath[path]; Select select = new Select() { SelectOperand = (Base.Data.Operand.Field) $"{alias}.{fieldName}", Alias = $"{alias}_{fieldName}" }; selectQuery.SelectList.Add(select); } selectQuery.WhereCondition = SearchCondition?.GetCondition(tableAliasesByFieldPath, upperFieldPath, queriesByFieldPath.Keys.Where(k => !string.IsNullOrEmpty(k)).ToArray()); queriesByFieldPath[""] = new Tuple <ISelectQuery, Dictionary <string, string> >(selectQuery, tableAliasesByFieldPath); return(queriesByFieldPath); }