public void CheckSemantics(IDslModel existingConcepts) { if (!(Subtype is IOrmDataStructure)) { throw new DslSyntaxException(this, "Is (polymorphic) may only be used on a database-mapped data structure, such as Entity or SqlQueryable. " + this.Subtype.GetUserDescription() + " is not IOrmDataStructure."); } if (ImplementationName == null) { throw new DslSyntaxException(this, "ImplementationName must not be null. It is allowed to be an empty string."); } if (!string.IsNullOrEmpty(ImplementationName)) { DslUtility.ValidateIdentifier(ImplementationName, this, "Invalid ImplementationName value."); } if (existingConcepts.FindByReference <PolymorphicMaterializedInfo>(pm => pm.Polymorphic, Supertype).Any()) { // Verifying if the ChangesOnChangedItemsInfo can be created (see IsSubtypeOfMacro) var dependsOn = DslUtility.GetBaseChangesOnDependency(Subtype, existingConcepts); if (dependsOn.Count() == 0) { throw new DslSyntaxException(this, Subtype.GetUserDescription() + " should be an *extension* of an entity. Otherwise it cannot be used in a materialized polymorphic entity because the system cannot detect when to update the persisted data."); } } }
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); }