/// <summary> /// Same subtype may implement same supertype multiple time. Since ID of the supertype is usually same as subtype's ID, /// that might result with multiple supertype records with the same ID. To avoid duplicate IDs and still keep the /// deterministic ID values, the supertype's ID is XORed by a hash code taken from the ImplementationName. /// </summary> private string GetSubtypeImplementationIdSnippet() { if (IsSubtypeOf.ImplementationName == "") { return(""); } else if (IsSubtypeOf.SupportsPersistedSubtypeImplementationColum()) { return(",\r\n SubtypeImplementationID = " + PersistedSubtypeImplementationIdInfo.GetComputedColumnName(IsSubtypeOf.ImplementationName)); } else { int hash = DomUtility.GetSubtypeImplementationHash(IsSubtypeOf.ImplementationName); return(",\r\n SubtypeImplementationID = CONVERT(UNIQUEIDENTIFIER, CONVERT(BINARY(4), CONVERT(INT, CONVERT(BINARY(4), ID)) ^ " + hash + ") + SUBSTRING(CONVERT(BINARY(16), ID), 5, 12))"); } }
public IEnumerable <IConceptInfo> CreateNewConcepts(IsSubtypeOfInfo conceptInfo, IDslModel existingConcepts) { var newConcepts = new List <IConceptInfo>(); // Add a subtype reference (for each subtype) to the supertype data structure: var subtypeReference = new PolymorphicSubtypeReferenceInfo { DataStructure = conceptInfo.Supertype, Referenced = conceptInfo.Subtype, Name = conceptInfo.GetSubtypeReferenceName() }; newConcepts.Add(subtypeReference); newConcepts.Add(new PolymorphicPropertyInfo { Property = subtypeReference }); // Minor optimization to reduce the number of macro evaluations. // Append subtype implementation to the supertype union: newConcepts.Add(new SubtypeExtendPolymorphicInfo { IsSubtypeOf = conceptInfo, SubtypeImplementationView = conceptInfo.GetImplementationViewPrototype(), PolymorphicUnionView = conceptInfo.Supertype.GetUnionViewPrototype() }); var filterBySubtypePrototype = new FilterByInfo { Source = conceptInfo.Supertype, Parameter = "Rhetos.Dom.DefaultConcepts.FilterSubtype" }; newConcepts.Add(new SubtypeExtendFilterInfo { IsSubtypeOf = conceptInfo, FilterBySubtype = filterBySubtypePrototype }); // Add metadata for supertype computation (union): foreach (DataStructureInfo dependsOn in DslUtility.GetBaseChangesOnDependency(conceptInfo.Subtype, existingConcepts)) { newConcepts.Add(new ChangesOnChangedItemsInfo { Computation = conceptInfo.Supertype, DependsOn = dependsOn, FilterType = "Rhetos.Dom.DefaultConcepts.FilterSubtype", FilterFormula = @"changedItems => new Rhetos.Dom.DefaultConcepts.FilterSubtype { Ids = changedItems.Select(" + GetComputeHashIdSelector(conceptInfo) + @").ToArray(), Subtype = " + CsUtility.QuotedString(conceptInfo.Subtype.Module.Name + "." + conceptInfo.Subtype.Name) + @", ImplementationName = " + CsUtility.QuotedString(conceptInfo.ImplementationName) + @" }" }); } // Add metadata for subtype implementation: PersistedSubtypeImplementationIdInfo subtypeImplementationColumn = null; if (conceptInfo.SupportsPersistedSubtypeImplementationColum()) { subtypeImplementationColumn = new PersistedSubtypeImplementationIdInfo { Subtype = conceptInfo.Subtype, ImplementationName = conceptInfo.ImplementationName }; newConcepts.Add(subtypeImplementationColumn); } // Automatic interface implementation: var implementationView = (SqlViewInfo)existingConcepts.FindByKey(conceptInfo.GetImplementationViewPrototype().GetKey()); if (implementationView == null) { implementationView = new ExtensibleSubtypeSqlViewInfo { IsSubtypeOf = conceptInfo }; newConcepts.Add(implementationView); if (subtypeImplementationColumn != null) { newConcepts.Add(new SqlDependsOnSqlObjectInfo { // The subtype implementation view will use the PersistedSubtypeImplementationColumn. DependsOn = subtypeImplementationColumn.GetSqlObjectPrototype(), Dependent = implementationView }); } } // Redirect the developer-provided SQL dependencies from the "Is" concept to the implementation view: newConcepts.AddRange(DslUtility.CopySqlDependencies(conceptInfo, implementationView, existingConcepts)); return(newConcepts); }