Background
Currently, ITopicRepository implementations rely on cached data in the TopicRepositoryBase's GetContentTypeDescriptors() method to validate metadata upon Save(). Notably, this is used by the SqlTopicRepository implementation to determine if an attribute should be stored as an indexed or an extended attribute.
Problem
This generally works fine. Problems are introduced, however, when the following conditions are true:
- An entire topic graph is being saved (e.g., as part of an
Import() using the OnTopic-Data-Exchange library), and
- The topic graph includes new
ContentTypeDescriptor or AttributeDescriptor instances not stored in the database.
Note: Issues #16 and #17 both seek to address a similar problem by updating the GetContentTypeDescriptors() cache when ContentTypeDescriptors or AttributeDescriptors are Save()d, Delete()d, or Move()d. But this doesn't address situations where a new Topic in a topic graph is being committed as part of a recursive Save() which will subsequently include new ContentTypeDescriptor or AttributeDescriptor instances.
Note: An obvious example of this is when bootstrapping a new database by importing a reference version of the OnTopic schema via a JSON file. How do you save the Root or Configuration before establishing the Container content type? This affects other scenarios as well, however.
Solution
This likely requires more consideration, but one option is to reactively update the GetContentTypeDescriptors() cache anytime the cache fails to deliver the a ContentTypeDescriptor or AttributeDescriptor by attempting to find that value in the current topic graph.
Note: The SqlTopicRepository doesn't maintain a local cached instance of the entire topic graph, as CachedTopicRepository does. As such, it can't do a fast local lookup on a canonical source. Still, the Topic being passed to Save() is presumably part of a larger topic graph, and thus new versions of content types may be able to be extracted from it. This would generally be expected, for example, in cases using the OnTopic-Data-Exchange library.
Implementation
Assuming the above solution makes sense, one possible implementation of this might look something like the following:
public class TopicRepositoryBase {
…
protected ContentTypeDescriptorCollection GetContentTypeDescriptors(Topic topic) =>
GetContentTypeDescriptors(GetRootContentType(topic));
private ContentTypeDescriptorCollection GetContentTypeDescriptors(ContentTypeDescriptor? topic) {
// Centralized logic from current GetContentTypeDescriptors() method
}
private ContentTypeDescriptor GetRootContentType(Topic topic, string ) {
while (topic.Parent == null) {
topic = topic.Parent;
}
var configuration = topic.Children.GetTopic("Configuration");
return configuration?.Children.GetTopic("ContentTypes") as ContentTypeDescriptor;
}
…
}
Note: It may be valuable to try generalizing and centralizing the GetRootContentType() as e.g. a GetTopicByUniqueKey() extension method so it can be reused elsewhere. This would be comparable to the CachedTopicRepository.GetTopic() method.
Background
Currently,
ITopicRepositoryimplementations rely on cached data in theTopicRepositoryBase'sGetContentTypeDescriptors()method to validate metadata uponSave(). Notably, this is used by theSqlTopicRepositoryimplementation to determine if an attribute should be stored as an indexed or an extended attribute.Problem
This generally works fine. Problems are introduced, however, when the following conditions are true:
Import()using the OnTopic-Data-Exchange library), andContentTypeDescriptororAttributeDescriptorinstances not stored in the database.Solution
This likely requires more consideration, but one option is to reactively update the
GetContentTypeDescriptors()cache anytime the cache fails to deliver the aContentTypeDescriptororAttributeDescriptorby attempting to find that value in the current topic graph.Implementation
Assuming the above solution makes sense, one possible implementation of this might look something like the following: