/// <summary> /// Loads the data model module. /// </summary> /// <param name="module">The module.</param> /// <param name="xdataModelModule">The xml fragment with data model information.</param> private static void LoadDataModelModule(DataModelModule module, XmlNode xdataModelModule) { XmlElement eDataModelModule = xdataModelModule as XmlElement; // Assign Id. module.Id = new Guid(eDataModelModule.Attributes[DataModellingResources.Id].Value); // Assign NameSpace. module.NameSpace = eDataModelModule.Attributes[DataModellingResources.Namespace].Value; // Assign Uri. module.Uri = eDataModelModule.HasAttribute(DataModellingResources.Uri) ? eDataModelModule.Attributes[DataModellingResources.Uri].Value : null; // Assign Description. module.Description = eDataModelModule.HasAttribute(DataModellingResources.Description) ? eDataModelModule.Attributes[DataModellingResources.Description].Value : null; // Clear internal lists. module.ResourceTypes.Clear(); // Load resource types before associations. LoadResourceTypeCollection(module.ResourceTypes, xdataModelModule.SelectNodes(DataModellingResources.XPathRelativeResourceType)); // Assign IsMsShipped in the end. module.IsMsShipped = Convert.ToInt32(xdataModelModule. Attributes[DataModellingResources.IsMsShipped].Value, CultureInfo.InvariantCulture) == 1 ? true : false; }
internal ResourceTypeCollection(DataModelModule parentModel) { // Set the parent property. if (parentModel == null) { throw new ZentityException(string.Format(CultureInfo.InvariantCulture, CoreResources.ExceptionArgumentIsNull, "parentModel")); } this.parent = parentModel; this.innerCollection = new Collection <ResourceType>(); }
/// <summary> /// Validates graph with the rules applicable to ManagerType triples and /// interprets ManagerType triples. /// </summary> /// <param name="dataModelModule">Instance of DataModelModule class to be updated.</param> internal override void Interpret(DataModelModule dataModelModule) { //Validate Graph Validate(); foreach (Triple triple in ClassTriples) { ResourceType newResRype = new ResourceType( GetLocalName(triple.TripleSubject as RDFUriReference), Context.BaseResourceType); newResRype.Uri = (triple.TripleSubject as RDFUriReference).InnerUri.AbsoluteUri; dataModelModule.ResourceTypes.Add(newResRype); } }
/// <summary> /// Validates graph with the rules applicable to SubClassOf triples and /// interprets SubClassOf triples. /// </summary> /// <param name="dataModelModule">Instance of DataModelModule class to be updated.</param> internal override void Interpret(DataModelModule dataModelModule) { Validate(); foreach (Triple triple in SubClassOfTriples) { ResourceType childClass = dataModelModule.ResourceTypes[GetLocalName( triple.TripleSubject as RDFUriReference)]; ResourceType parentClass = dataModelModule.ResourceTypes[GetLocalName( triple.TripleObject as RDFUriReference)]; childClass.BaseType = parentClass; } }
/// <summary> /// Adds the scalar property. /// </summary> /// <param name="domainTriple">The domain triple.</param> /// <param name="rangeTriple">The range triple.</param> /// <param name="dataModelModule">The data model module.</param> private void AddScalarProperty(Triple domainTriple, Triple rangeTriple, DataModelModule dataModelModule) { //Get property name. string propertyName = GetLocalName(domainTriple.TripleSubject as RDFUriReference); //Get resource type. ResourceType domainResType = dataModelModule.ResourceTypes[ GetLocalName(domainTriple.TripleObject as RDFUriReference)]; XsdDataType dataType = Context.XsdDataTypeCollection. Where(tuple => tuple.Name == rangeTriple.TripleObject).First(); //Create scalar property and add to resource type. ScalarProperty property = new ScalarProperty(propertyName, dataType.BaseType); property.MaxLength = dataType.MaxLength; property.Precision = dataType.Precision; property.Scale = dataType.Scale; domainResType.ScalarProperties.Add(property); }
private void AddNavigationProperty(Triple domainTriple, Triple rangeTriple, DataModelModule dataModelModule) { //Get property name. string propertyName = GetLocalName(domainTriple.TripleSubject as RDFUriReference); //Get subject resource type. ResourceType subjectResType = dataModelModule.ResourceTypes[ GetLocalName(domainTriple.TripleObject as RDFUriReference)]; //Create subject navigation property and add to subject resource type. NavigationProperty subProperty = new NavigationProperty(); subProperty.Name = propertyName; subProperty.Uri = (rangeTriple.TripleSubject as RDFUriReference).InnerUri.AbsoluteUri; subjectResType.NavigationProperties.Add(subProperty); //Get object resource type. ResourceType objectResType = dataModelModule.ResourceTypes[ GetLocalName(rangeTriple.TripleObject as RDFUriReference)]; //Create object navigation property and add to object resource type. NavigationProperty objProperty = new NavigationProperty(); objProperty.Name = string.Format(CultureInfo.InvariantCulture, propertyNameFormat, propertyName); objProperty.Uri = string.Format(CultureInfo.InvariantCulture, propertyNameFormat, (rangeTriple.TripleSubject as RDFUriReference).InnerUri.AbsoluteUri); objectResType.NavigationProperties.Add(objProperty); //Create Association object. string assName = string.Format(CultureInfo.InvariantCulture, associationNameFormat, subjectResType.Name, subProperty.Name, objectResType.Name); Association association = new Association(assName) { SubjectNavigationProperty = subProperty, ObjectNavigationProperty = objProperty }; }
private static void CompareDataModelModules(ModuleCollectionChange changes, DataModelModuleCollection originalModules, DataModelModuleCollection targetModules) { // Compute added modules. List <Guid> addedGuids = new List <Guid>(); addedGuids.AddRange(targetModules.Select(tuple => tuple.Id). Except(originalModules.Select(tuple => tuple.Id))); changes.AddedDataModelModules.AddRange(targetModules. Where(tuple => addedGuids.Contains(tuple.Id))); // Compute removed modules. List <Guid> removedGuids = new List <Guid>(); removedGuids.AddRange(originalModules.Select(tuple => tuple.Id). Except(targetModules.Select(tuple => tuple.Id))); changes.DeletedDataModelModules.AddRange(originalModules. Where(tuple => removedGuids.Contains(tuple.Id))); // Compute updated modules. We ignore the parent property of the modules. foreach (DataModelModule originalModule in originalModules) { DataModelModule newModule = targetModules. Where(tuple => tuple.Id == originalModule.Id).FirstOrDefault(); if (newModule != null) { if (originalModule.Description != newModule.Description || originalModule.NameSpace != newModule.NameSpace || originalModule.Uri != newModule.Uri) { changes.UpdatedDataModelModules.Add(originalModule, newModule); } } } }
/// <summary> /// Interprets Domain and Range triples. /// </summary> /// <param name="dataModelModule">Instance of DataModelModule class to be updated.</param> internal override void Interpret(DataModelModule dataModelModule) { // Validate domain and range triple rules. Validate(); foreach (Triple triple in PropertyTriples) { //Get range and domain triples. Triple rangeTriple = RangeTriples. Where(tuple => tuple.TripleSubject == triple.TripleSubject).First(); Triple domainTriple = DomainTriples. Where(tuple => tuple.TripleSubject == triple.TripleSubject).First(); //Add property. if (IsScalarProperty(rangeTriple.TripleObject as RDFUriReference)) { AddScalarProperty(domainTriple, rangeTriple, dataModelModule); } else { AddNavigationProperty(domainTriple, rangeTriple, dataModelModule); } } }
/// <summary> /// When overriden by derived classes interpets the triples in the graph. /// </summary> /// <param name="dataModelModule">Instance of DataModelModule class to be updated.</param> internal abstract void Interpret(DataModelModule dataModelModule);
/// <summary> /// Loads the data model module collection. /// </summary> /// <param name="inputModules">The input modules.</param> /// <param name="xDataModel">The xml document with data model information.</param> private static void LoadDataModelModuleCollection(DataModelModuleCollection inputModules, XmlDocument xDataModel) { // We load the module collection in three passes. // Pass1 - Create all resource types, scalar and navigation properties but do not // assign base types to the resource types. This allows us to process the derived // types before the base types. Otherwise, we might run into scenarios where we do // not have a base type reference while processing a derived type. // Pass2 - Assign base types to all resource types. // Pass3 - Create associations between various navigation properties. // Pass1 - Create all resource types, scalar and navigation properties but do not // assign base types to the resource types. foreach (XmlNode xModule in xDataModel.SelectNodes(DataModellingResources.XPathDataModelModule)) { DataModelModule module = new DataModelModule(); inputModules.Add(module); LoadDataModelModule(module, xModule); } // Pass2 - Assign base types to all resource types. foreach (XmlNode xResourceType in xDataModel.SelectNodes(DataModellingResources.XPathResourceType)) { XmlElement eResourceType = xResourceType as XmlElement; Guid id = new Guid(eResourceType.Attributes[DataModellingResources.Id].Value); // Assign BaseType. if (eResourceType.HasAttribute(DataModellingResources.BaseTypeId)) { Guid baseResourceTypeId = new Guid(eResourceType.Attributes[DataModellingResources.BaseTypeId].Value); ResourceType derivedType = GetResourceTypeById(inputModules, id); derivedType.BaseType = GetResourceTypeById(inputModules, baseResourceTypeId); } } // Pass3 - Create associations between various navigation properties. foreach (XmlNode xAssociation in xDataModel.SelectNodes(DataModellingResources.XPathAssociation)) { XmlElement eAssociation = xAssociation as XmlElement; Association association = new Association(); // Assign Id. association.Id = new Guid(eAssociation.Attributes[DataModellingResources.Id].Value); // Assign Name. association.Name = eAssociation.Attributes[DataModellingResources.Name].Value; // Assign Uri. association.Uri = eAssociation.HasAttribute(DataModellingResources.Uri) ? eAssociation.Attributes[DataModellingResources.Uri].Value : null; // Assign subject navigation property. Guid subjectNavigationPropertyId = new Guid(eAssociation. Attributes[DataModellingResources.SubjectNavigationPropertyId].Value); association.SubjectNavigationProperty = GetNavigationPropertyById(inputModules, subjectNavigationPropertyId); // Assign object navigation property. Guid objectNavigationPropertyId = new Guid(eAssociation. Attributes[DataModellingResources.ObjectNavigationPropertyId].Value); association.ObjectNavigationProperty = GetNavigationPropertyById(inputModules, objectNavigationPropertyId); // Assign predicate id. association.PredicateId = new Guid(eAssociation. Attributes[DataModellingResources.PredicateId].Value); // Assign subject multiplicity. string subjectMultiplicity = eAssociation.Attributes[DataModellingResources.SubjectMultiplicity].Value; association.SubjectMultiplicity = (AssociationEndMultiplicity)Enum. Parse(typeof(AssociationEndMultiplicity), subjectMultiplicity); // Assign object multiplicity. string objectMultiplicity = eAssociation.Attributes[DataModellingResources.ObjectMultiplicity].Value; association.ObjectMultiplicity = (AssociationEndMultiplicity)Enum. Parse(typeof(AssociationEndMultiplicity), objectMultiplicity); // Assign view name. association.ViewName = eAssociation.Attributes[DataModellingResources.ViewName].Value; } }
/// <summary> /// Parses object model defined in RDFS/XML to DataModelModule object. /// </summary> /// <param name="baseResourceType">Instance of Base ResourceType.</param> /// <param name="rdfDocument">RDF/XML Document.</param> /// <param name="xsdDocument">XSD Documet.</param> /// <param name="namespaceName">User defined Namespace.</param> /// <param name="isStrictExecutionMode">Execution Mode (Strict/Loose).</param> /// <returns>Parsed object of DataModelModule class.</returns> /// <exception cref="Zentity.Rdf.Xml.RdfXmlParserException"/> /// <exception cref="Zentity.Core.RdfsException"/> /// <example> This example shows how to create a <see cref="Zentity.Core.DataModelModule"/> /// from an RDF Schema document. Though, the example uses reflection to show how to use the /// generated assembly, we recommend creating clients that are compiled with references to /// the extensions assembly to avoid the reflection based code. /// <br/> /// The listing below shows the contents of RDF Schema document. The example assumes that /// this document is saved as 'C:\Sample.rdf'. /// <code lang="xml"> ///<?xml version="1.0"?> ///<!DOCTYPE rdf:RDF [ /// <!ENTITY dt "http://contoso.com/2008/" > ///]> ///<rdf:RDF /// xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" /// xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" /// xml:base="http://www.sample.org/"> /// /// <rdfs:Class rdf:about="Person"> /// </rdfs:Class> /// /// <rdfs:Class rdf:about="Employee"> /// <rdfs:subClassOf rdf:resource="Person"/> /// </rdfs:Class> /// /// <rdfs:Class rdf:about="Book"> /// </rdfs:Class> /// /// <rdf:Property rdf:about="AuthoredBy"> /// <rdfs:range rdf:resource="Person"/> /// <rdfs:domain rdf:resource="Book"/> /// </rdf:Property> /// /// <rdf:Property rdf:about="EditedBy"> /// <rdfs:range rdf:resource="Person"/> /// <rdfs:domain rdf:resource="Book"/> /// </rdf:Property> /// /// <rdf:Property rdf:about="Name"> /// <rdfs:range rdf:resource="&dt;string128"/> /// <rdfs:domain rdf:resource="Person"/> /// </rdf:Property> /// /// <rdf:Property rdf:about="Designation"> /// <rdfs:range rdf:resource="&dt;string256"/> /// <rdfs:domain rdf:resource="Employee"/> /// </rdf:Property> /// /// <rdf:Property rdf:about="//Book/Name"> /// <rdfs:range rdf:resource="&dt;string128"/> /// <rdfs:domain rdf:resource="Book"/> /// </rdf:Property> /// ///</rdf:RDF> /// </code> /// <br/> /// The listing below shows the contents of XSD that contains additional type definitions /// used in the example. The example assumes that this document is saved as 'C:\Sample.xsd'. /// <code lang="xml"> ///<xs:schema /// targetNamespace="http://contoso.com/2008/" /// xmlns:xs="http://www.w3.org/2001/XMLSchema"> /// /// <xs:simpleType name="string128" id="string128"> /// <xs:restriction base="xs:string"> /// <xs:maxLength value="128"/> /// </xs:restriction> /// </xs:simpleType> /// /// <xs:simpleType name="string256" id="string256"> /// <xs:restriction base="xs:string"> /// <xs:maxLength value="256"/> /// </xs:restriction> /// </xs:simpleType> /// ///</xs:schema> /// </code> /// <br/> /// Example: /// <code> ///using System; ///using System.Linq; ///using Zentity.Core; ///using System.Reflection; ///using System.Collections; ///using System.Xml.Linq; /// ///namespace ZentitySamples ///{ /// class Program /// { /// const string nameSpace = "Zentity.Samples"; /// const string connectionStringFormat = @"provider=System.Data.SqlClient; /// metadata=res://{0}; provider connection string='Data Source=.; /// Initial Catalog=Zentity;Integrated Security=True;MultipleActiveResultSets=True'"; /// const string rdfsPath = @"C:\Sample.rdf"; /// const string dataTypesXsdPath = @"C:\Sample.xsd"; /// const string extensionsAssemblyName = "Extensions"; /// const string extensionsAssemblyFileName = "Extensions.dll"; /// /// static void Main(string[] args) /// { /// Assembly extensions = SynchronizeAndGenerateAssembly(); /// CreateRepositoryItems(extensions); /// FetchRepositoryItems(extensions); /// } /// /// private static void FetchRepositoryItems(Assembly extensionsAssembly) /// { /// using (ZentityContext context = new ZentityContext( /// string.Format(connectionStringFormat, extensionsAssemblyName))) /// { /// Console.WriteLine("Getting books..."); /// Type resourceTypeBook = extensionsAssembly.GetType("Zentity.Samples.Book"); /// MethodInfo ofTypeMethod = context.Resources.GetType().GetMethod("OfType"). /// MakeGenericMethod(resourceTypeBook); /// var customTypeInstances = ofTypeMethod.Invoke(context.Resources, null); /// foreach (Resource book in (IEnumerable)customTypeInstances) /// Console.WriteLine(book.Id); /// /// Console.WriteLine("\nGetting persons..."); /// Type resourceTypePerson = extensionsAssembly.GetType("Zentity.Samples.Person"); /// ofTypeMethod = context.Resources.GetType().GetMethod("OfType"). /// MakeGenericMethod(resourceTypePerson); /// customTypeInstances = ofTypeMethod.Invoke(context.Resources, null); /// foreach (Resource person in (IEnumerable)customTypeInstances) /// Console.WriteLine(person.Id); /// /// Console.WriteLine("\nGetting AuthoredBy relationships..."); /// NavigationProperty authoredByProperty = context.DataModel.Modules[nameSpace]. /// ResourceTypes["Book"].NavigationProperties["AuthoredBy"]; /// Predicate predicate = context.Predicates. /// Where(tuple => tuple.Id == authoredByProperty.Association.PredicateId).First(); /// predicate.Relationships.Load(); /// foreach (Relationship rel in predicate.Relationships) /// Console.WriteLine("[{0}] <--{1}--> [{2}]", rel.Subject.Id, predicate.Name, /// rel.Object.Id); /// } /// } /// /// private static void CreateRepositoryItems(Assembly extensionsAssembly) /// { /// using (ZentityContext context = new ZentityContext( /// string.Format(connectionStringFormat, extensionsAssemblyName))) /// { /// Type resourceTypeBook = extensionsAssembly.GetType("Zentity.Samples.Book"); /// PropertyInfo propertyAuthoredBy = resourceTypeBook.GetProperty("AuthoredBy"); /// Type resourceTypePerson = extensionsAssembly.GetType("Zentity.Samples.Person"); /// /// var aPerson = Activator.CreateInstance(resourceTypePerson); /// var aBook = Activator.CreateInstance(resourceTypeBook); /// var anotherBook = Activator.CreateInstance(resourceTypeBook); /// /// // AuthoredBy is actually a an EntityCollection<Person>. /// var instanceAuthoredBy = propertyAuthoredBy.GetValue(aBook, null); /// Type entityCollectionOfPerson = instanceAuthoredBy.GetType(); /// // Get the "Add" method. /// MethodInfo methodAdd = entityCollectionOfPerson.GetMethod("Add"); /// // Add author to book. /// methodAdd.Invoke(instanceAuthoredBy, new object[] { aPerson }); /// /// instanceAuthoredBy = propertyAuthoredBy.GetValue(anotherBook, null); /// methodAdd.Invoke(instanceAuthoredBy, new object[] { aPerson }); /// /// // Save the entities to repository. /// context.AddToResources((Resource)aPerson); /// context.SaveChanges(); /// } /// } /// /// private static Assembly SynchronizeAndGenerateAssembly() /// { /// using (ZentityContext context = new ZentityContext( /// string.Format(connectionStringFormat, "Zentity.Core"))) /// { /// ResourceType defaultBaseResourceType = context.DataModel. /// Modules["Zentity.Core"].ResourceTypes["Resource"]; /// /// XDocument rdfDocument = XDocument.Load(rdfsPath); /// XDocument xsdDocument = XDocument.Load(dataTypesXsdPath); /// DataModelModule module = DataModelModule.CreateFromRdfs(defaultBaseResourceType, /// rdfDocument, xsdDocument, nameSpace, false); /// /// context.DataModel.Modules.Add(module); /// /// // Synchronize to alter the database schema. /// // This method sometimes takes a few minutes to complete depending on the actions /// // taken by other modules (such as change history logging) in response to schema /// // changes. Everything happens in a single transaction. Make sure that the timeout /// // values are set correct for the command and transaction. Transaction timeout is /// // controlled from App.Config, Web.Config and machine.config configuration files. /// context.CommandTimeout = 300; /// context.DataModel.Synchronize(); /// /// // Generate the module assembly to use. /// byte[] rawAssembly = context.DataModel.GenerateExtensionsAssembly( /// extensionsAssemblyName, true, new string[] { nameSpace }, /// new string[] { nameSpace }, null); /// /// return Assembly.Load(rawAssembly); /// } /// } /// } ///} /// </code> /// </example> public static DataModelModule CreateFromRdfs(ResourceType baseResourceType, XDocument rdfDocument, XDocument xsdDocument, string namespaceName, bool isStrictExecutionMode) { //Validate parameters. if (baseResourceType == null) { throw new ArgumentNullException("baseResourceType", RdfsResources.ExceptionArgumentIsNull); } if (rdfDocument == null) { throw new ArgumentNullException("rdfDocument", RdfsResources.ExceptionArgumentIsNull); } if (string.IsNullOrEmpty(namespaceName)) { throw new ArgumentNullException("namespaceName", RdfsResources.ExceptionArgumentIsNull); } ExecutionMode executionMode = isStrictExecutionMode ? ExecutionMode.Strict : ExecutionMode.Loose; //Parse Rdf/Xml to Graph. RdfXmlParser rdfParser = new RdfXmlParser(rdfDocument); Graph rdfGraph = rdfParser.Parse(true); //Create collection of xsd datatypes. XsdDataTypeCollection dataTypeCollection = null; if (xsdDocument != null) { dataTypeCollection = new XsdDataTypeCollection(xsdDocument); } else { dataTypeCollection = new XsdDataTypeCollection(); } //Create context for current execution. Context context = new Context { Graph = rdfGraph, XsdDataTypeCollection = dataTypeCollection, ExecutionMode = executionMode, BaseResourceType = baseResourceType }; //Create list of interpreters. List <RdfsInterpreter> interpreters = new List <RdfsInterpreter>(); interpreters.Add(new PredicateInterpreter(context)); interpreters.Add(new TypeInterpreter(context)); interpreters.Add(new SubClassOfInterpreter(context)); interpreters.Add(new DomainRangeInterpreter(context)); //Create data model module object. DataModelModule dataModelModule = new DataModelModule { NameSpace = namespaceName, Uri = rdfDocument.BaseUri }; //Execute interpreters. foreach (RdfsInterpreter interpreter in interpreters) { interpreter.Interpret(dataModelModule); } return(dataModelModule); }
/// <summary> /// Validates Graph with the rules applicable to predicates. /// </summary> /// <param name="dataModelModule">Instance of DataModelModule class to be updated.</param> internal override void Interpret(DataModelModule dataModelModule) { Validate(); }