public DataSchema GetSchema()
        {
            if (CachedDataSchema != null)
            {
                return(CachedDataSchema);
            }

            lock (this) {
                if (CachedDataSchema != null)
                {
                    return(CachedDataSchema);
                }

                var schema = new DataSchema();
                InitSuperClassSchema(schema);
                CachedDataSchema = schema;

                // load all OWL classes
                var owlClassIds = ObjectStorage.GetObjectIds(new Query(OwlConfig.SuperClassID));
                var owlClassMap = ObjectStorage.Load(owlClassIds);
                InitMetaSchema(schema, owlClassMap.Values);

                // load data schema described in OWL terms
                InitDataSchema(schema);
            }

            return(CachedDataSchema);
        }
        public void CreateDatatypeProperty(string id, string label, PropertyDataType dataType, bool isFunctional = true)
        {
            var schema            = GetSchema();
            var datatypePropClass = schema.FindClassByID(OwlConfig.DatatypePropertyClassID);
            var rangeClass        = schema.FindClassByID(OwlConfig.RangeClassID);
            var rdfTypeClass      = schema.FindClassByID(OwlConfig.RdfTypeClassID);
            var funcPropClass     = schema.FindClassByID(OwlConfig.FunctionalPropertyClassID);

            var datatypePropRangeRel   = datatypePropClass.FindRelationship(rangeClass, schema.FindClassByID(OwlConfig.DatatypeClassID));
            var datatypePropRdfTypeRel = datatypePropClass.FindRelationship(rdfTypeClass, schema.FindClassByID(OwlConfig.SuperClassID));

            var dataTypeIds = ObjectStorage.GetObjectIds(new Query(OwlConfig.DatatypeClassID, (QField)OwlConfig.SuperIdPropertyID == new QConst(dataType.ID)));

            if (dataTypeIds.Length != 1)
            {
                throw new ArgumentException("Cannot locate object for datatype ID=" + dataType.ID);
            }

            var dtPropObj = new ObjectContainer(datatypePropClass);

            dtPropObj[OwlConfig.SuperIdPropertyID] = id;
            dtPropObj[OwlConfig.LabelClassID]      = label;
            ObjectStorage.Insert(dtPropObj);

            if (isFunctional)
            {
                ObjectStorage.AddRelation(new ObjectRelation(dtPropObj.ID.Value, datatypePropRdfTypeRel, funcPropClass.CompactID));
            }
            ObjectStorage.AddRelation(new ObjectRelation(dtPropObj.ID.Value, datatypePropRangeRel, dataTypeIds[0]));

            Refresh();
        }
        protected void InitDataSchema(DataSchema schema)
        {
            var objectClassIds       = ObjectStorage.GetObjectIds(new Query(OwlConfig.ObjectClassID));
            var datatypePropClassIds = ObjectStorage.GetObjectIds(new Query(OwlConfig.DatatypePropertyClassID));
            var objPropClassIds      = ObjectStorage.GetObjectIds(new Query(OwlConfig.ObjectPropertyClassID));
            var datatypeIds          = ObjectStorage.GetObjectIds(new Query(OwlConfig.DatatypeClassID));

            var allIds = new List <long>();

            allIds.AddRange(objectClassIds);
            allIds.AddRange(datatypePropClassIds);
            allIds.AddRange(objPropClassIds);
            allIds.AddRange(datatypeIds);

            var idToObj = ObjectStorage.Load(allIds.ToArray());

            foreach (var metaClassObj in objectClassIds.Select(o => idToObj[o]))
            {
                var id = metaClassObj[OwlConfig.SuperIdPropertyID] as string;
                if (id != null)
                {
                    var name = (metaClassObj[OwlConfig.LabelClassID] as string) ?? id;
                    var c    = new Class(id)
                    {
                        CompactID = metaClassObj.ID.Value,
                        Name      = name
                    };
                    schema.AddClass(c);
                    schema.AddClassProperty(new ClassPropertyLocation(c, schema.FindPropertyByID(OwlConfig.PkPropertyID), ObjectPkColumn));
                }
            }

            var allDatatypePropObjects = datatypePropClassIds.Select(o => idToObj[o]).ToArray();

            foreach (var metaPropObj in allDatatypePropObjects)
            {
                var id = metaPropObj[OwlConfig.SuperIdPropertyID] as string;
                if (id != null)
                {
                    var name = (metaPropObj[OwlConfig.LabelClassID] as string) ?? id;
                    schema.AddProperty(new Property(id)
                    {
                        CompactID  = metaPropObj.ID.Value,
                        Name       = name,
                        Multivalue = true,                         // by default all props are multivalue in OWL
                        PrimaryKey = id == OwlConfig.PkPropertyID,
                        DataType   = PropertyDataType.String       // default type used for properties without explicit range definition
                    });
                }
            }

            var allObjPropObjects = objPropClassIds.Select(o => idToObj[o]).ToArray();

            foreach (var obj in allObjPropObjects)
            {
                var id = obj[OwlConfig.SuperIdPropertyID] as string;
                if (id != null)
                {
                    var name = (obj[OwlConfig.LabelClassID] as string) ?? id;
                    var c    = new Class(id)
                    {
                        CompactID   = obj.ID.Value,
                        Name        = name,
                        IsPredicate = true
                    };
                    schema.AddClass(c);
                }
            }

            var superClass        = schema.FindClassByID(OwlConfig.SuperClassID);
            var datatypePropClass = schema.FindClassByID(OwlConfig.DatatypePropertyClassID);
            var datatypeClass     = schema.FindClassByID(OwlConfig.DatatypeClassID);
            var domainClass       = schema.FindClassByID(OwlConfig.DomainClassID);
            var rangeClass        = schema.FindClassByID(OwlConfig.RangeClassID);
            var objClass          = schema.FindClassByID(OwlConfig.ObjectClassID);
            var rdfTypeClass      = schema.FindClassByID(OwlConfig.RdfTypeClassID);
            var funcPropClass     = schema.FindClassByID(OwlConfig.FunctionalPropertyClassID);
            var invFuncPropClass  = schema.FindClassByID(OwlConfig.InverseFunctionalPropertyClassID);

            // resolve datatype properties
            var dataTypePropRels = ObjectStorage.LoadRelations(allDatatypePropObjects,
                                                               new [] {
                datatypePropClass.FindRelationship(rangeClass, datatypeClass),
                datatypePropClass.FindRelationship(domainClass, objClass),
                datatypePropClass.FindRelationship(rdfTypeClass, superClass)
            });
            var dataTypeMap = BuildDataTypeMap(datatypeIds, idToObj);

            foreach (var rangeRel in dataTypePropRels.Where(r => r.Relation.Predicate == rangeClass))
            {
                var p = schema.FindPropertyByCompactID(rangeRel.SubjectID);
                if (dataTypeMap.ContainsKey(rangeRel.ObjectID))
                {
                    p.DataType = dataTypeMap[rangeRel.ObjectID];
                }
            }

            foreach (var funcPropRel in dataTypePropRels.Where(r => r.Relation.Predicate == rdfTypeClass && r.ObjectID == funcPropClass.CompactID))
            {
                var p = schema.FindPropertyByCompactID(funcPropRel.SubjectID);
                p.Multivalue = false;
            }

            foreach (var domainRel in dataTypePropRels.Where(r => r.Relation.Predicate == domainClass))
            {
                var p = schema.FindPropertyByCompactID(domainRel.SubjectID);
                var c = schema.FindClassByCompactID(domainRel.ObjectID);
                if (c != null && p != null)
                {
                    AddClassProperty(schema, new ClassPropertyLocation(c, p));
                }
            }

            // resolve object properties into relationships
            var objPropClass     = schema.FindClassByID(OwlConfig.ObjectPropertyClassID);
            var objPropRangeRel  = objPropClass.FindRelationship(rangeClass, objClass);
            var objPropDomainRel = objPropClass.FindRelationship(domainClass, objClass);

            var objPropRels = ObjectStorage.LoadRelations(allObjPropObjects,
                                                          new [] {
                objPropClass.FindRelationship(domainClass, objClass),
                objPropClass.FindRelationship(rangeClass, objClass),
                objPropClass.FindRelationship(rdfTypeClass, superClass),
                // TBD: subclass-of to avoid these duplicate relationships
                objPropClass.FindRelationship(domainClass, superClass),
                objPropClass.FindRelationship(rangeClass, superClass)
            });

            foreach (var predicateClass in schema.Classes.Where(c => c.IsPredicate))
            {
                var predRels = objPropRels.Where(r => r.SubjectID == predicateClass.CompactID).ToArray();
                foreach (var domainRel in predRels.Where(r => r.Relation.Predicate == domainClass))
                {
                    foreach (var rangeRel in predRels.Where(r => r.Relation.Predicate == rangeClass))
                    {
                        var rSubjClass = schema.FindClassByCompactID(domainRel.ObjectID);
                        var rObjClass  = schema.FindClassByCompactID(rangeRel.ObjectID);

                        var subjectMultiplicity = !predRels.Any(r => r.Relation.Predicate == rdfTypeClass && r.ObjectID == invFuncPropClass.CompactID);
                        var objectMultiplicity  = !predRels.Any(r => r.Relation.Predicate == rdfTypeClass && r.ObjectID == funcPropClass.CompactID);
                        var revRelationship     = new Relationship(rObjClass, predicateClass, rSubjClass, subjectMultiplicity, true, null);
                        schema.AddRelationship(new Relationship(rSubjClass, predicateClass, rObjClass, objectMultiplicity, false, revRelationship));
                        schema.AddRelationship(revRelationship);
                    }
                }
            }
        }