/// <summary> /// Handles a relationship downcast. (For example, where a relationship returns all actors, but only types derived from People should be shown). /// </summary> /// <param name="downcast"></param> /// <param name="parentTable">The parent table.</param> /// <param name="sqlQuery">The SQL query that the table will be created in.</param> /// <returns>The table to use for upward joins.</returns> private EntityTables RegisterDownCastResourceEntity(DownCastResource downcast, SqlTable parentTable, SqlQuery sqlQuery) { // Note: generally we are able to completely reuse the parent table, as it already selects the entities we require. // Additional filtering is only applied if explicitly requested. SqlTable entityTable = parentTable; if (downcast.MustExist) { // Just constrain the parent table directly ConstrainDefinitionType(parentTable, downcast.EntityTypeId, downcast.ExactType, sqlQuery); } else if (downcast.ExactType) { // If we want the exact type, but don't want to constrain the parent with a must exist, then we // must rejoin to entity table so we can have one constrained table, and one unconstrained one. entityTable = sqlQuery.CreateJoinedTable("dbo.Entity", "dc", parentTable, JoinHint.Unspecified, "Id", parentTable.IdColumn); entityTable.IdColumn = "Id"; ConstrainDefinitionType(entityTable, downcast.EntityTypeId, true, sqlQuery); } // If MustExist=false and ExactType=false (the typical case) we just reuse the parent table without adding any constraints, // and just rely on the fact that incorrect types simply won't have any data for the requested fields or relationships. return(new EntityTables { EntityTable = entityTable, HeadTable = parentTable }); }
/// <summary> /// Return true if we cannot /// </summary> /// <param name="node"></param> /// <returns></returns> private static bool NodeMightCauseSomeRowsToNotAppear(SQ.Entity node) { // Check flags on the node RelatedResource relNode = node as RelatedResource; if (relNode != null) { if (relNode.ResourceMustExist || relNode.CheckExistenceOnly || relNode.ConstrainParent) { return(true); } } else { DownCastResource derivedNode = node as DownCastResource; if (derivedNode != null) { if (derivedNode.MustExist) { return(true); } } else { if (node is AggregateEntity) { return(false); // aggregates will always give us something } else { return(true); } } } // Check children if (node.RelatedEntities.Any(NodeMightCauseSomeRowsToNotAppear)) { return(true); } return(false); }
/// <summary> /// Builds the derived type report node. /// </summary> /// <param name="reportNode">The report node.</param> /// <param name="context">The context.</param> /// <returns>DownCastResource.</returns> private static DownCastResource BuildDerivedTypeReportNode(DerivedTypeReportNode reportNode, FromEntityContext context) { DownCastResource downCastResource = new DownCastResource { MustExist = reportNode.TargetMustExist ?? false, ExactType = reportNode.ExactType ?? false }; if (reportNode.ResourceReportNodeType != null) { downCastResource.EntityTypeId = reportNode.ResourceReportNodeType.Id; } Guid nodeId; if (!context.ReportNodeMap.TryGetValue(reportNode.Id, out nodeId)) { nodeId = Guid.NewGuid(); context.ReportNodeMap[reportNode.Id] = nodeId; } downCastResource.NodeId = nodeId; downCastResource.EntityId = reportNode.Id; return(downCastResource); }