Current filter:
                                You should refresh the page.
                                  • We cannot create persistent classes declaratively, because our users' requirement is the capability to view data from an arbitrary database. We do not know the structure of the database before the application starts. What is the best way to create such an application?

                                    Search keywords: dynamically, dynamic, runtime, structure, custom, member, class, attribute, XPDictionary, ReflectionDictionary, XPClassInfo, XPMemberInfo, XPTypeInfo

                                1 Solution

                                Creation Date Importance Sort by

                                For this task, XPO provides the capability to define persistent classes on the fly, without defining any classes in code, except for the class that will be used as the base class for dynamically created metadata. This class should provide a constructor with the XPClassInfo parameter. The code below is quite enough for this:

                                [NonPersistent] public class BasePersistentClass :XPLiteObject { public BasePersistentClass(Session session) : base(session) { } public BasePersistentClass(Session session, XPClassInfo classInfo) : base(session, classInfo) { } }
                                <NonPersistent> _ Public Class BasePersistentClass Inherits XPLiteObject Public Sub New(ByVal session As Session) MyBase.New(session) End Sub Public Sub New(ByVal session As Session, ByVal classInfo As XPClassInfo) MyBase.New(session, classInfo) End Sub End Class

                                You can create virtual classes using the XPDictionary.CreateClass method. This method creates a new instance of XPClassInfo, and also adds it to the XPDictionary.Classes collection. The XPClassInfo.CreateMember method will create a new XPCustomMemberInfo instance, and add it to the XPClassInfo.Members collection. For example:

                                XPDictionary dictionary = new ReflectionDictionary(); XPClassInfo classInfo = dictionary.CreateClass(dictionary.GetClassInfo(typeof(BasePersistentClass)), "MyClass"); XPMemberInfo memberInfo = classInfo.CreateMember("MyProperty", typeof(string));
                                Dim dictionary As XPDictionary = New ReflectionDictionary() Dim classInfo As XPClassInfo = dictionary.CreateClass(dictionary.GetClassInfo(GetType(BasePersistentClass)), "MyClass") Dim memberInfo As XPMemberInfo = classInfo.CreateMember("MyProperty", GetType(String))

                                The ConnectionProviderSql class provides two methods that can be used to retrieve the database schema. The ConnectionProviderSql.GetStorageTablesList method returns an array of string values, representing table names in the database. The table names can be passed as parameters to the ConnectionProviderSql.GetStorageTables method, which will return an array of DBTable instances, describing the schema of specified tables. Here is the code of the method that creates persistent metadata based on a DBTable instance:

                                public static XPClassInfo AddClass(XPDictionary dict, DBTable table) { if (table.PrimaryKey.Columns.Count > 1) throw new NotSupportedException("Compound primary keys are not supported"); XPClassInfo classInfo = dict.CreateClass(dict.GetClassInfo(typeof(BasePersistentClass)), table.Name.Replace('.', '_')); classInfo.AddAttribute(new PersistentAttribute(table.Name)); DBColumnType primaryColumnType = table.GetColumn(table.PrimaryKey.Columns[0]).ColumnType; classInfo.CreateMember(table.PrimaryKey.Columns[0], DBColumn.GetType(primaryColumnType), new KeyAttribute(IsAutoGenerationSupported(primaryColumnType))); foreach (DBColumn col in table.Columns) if (!col.IsKey) classInfo.CreateMember(col.Name, DBColumn.GetType(col.ColumnType)); return classInfo; } static bool IsAutoGenerationSupported(DBColumnType type) { return type == DBColumnType.Guid || type == DBColumnType.Int16 || type == DBColumnType.Int32; }
                                Public Shared Function AddClass(ByVal dict As XPDictionary, ByVal table As DBTable) As XPClassInfo If table.PrimaryKey.Columns.Count > 1 Then Throw New NotSupportedException("Compound primary keys are not supported") End If Dim classInfo As XPClassInfo = dict.CreateClass(dict.GetClassInfo(GetType(BasePersistentClass)), table.Name.Replace("."c, "_"c)) classInfo.AddAttribute(New PersistentAttribute(table.Name)) Dim primaryColumnType As DBColumnType = table.GetColumn(table.PrimaryKey.Columns(0)).ColumnType classInfo.CreateMember(table.PrimaryKey.Columns(0), DBColumn.GetType(primaryColumnType), New KeyAttribute(IsAutoGenerationSupported(primaryColumnType))) For Each col As DBColumn In table.Columns If (Not col.IsKey) Then classInfo.CreateMember(col.Name, DBColumn.GetType(col.ColumnType)) End If Next col Return classInfo End Function Shared Function IsAutoGenerationSupported(ByVal type As DBColumnType) As Boolean Return type = DBColumnType.Guid OrElse type = DBColumnType.Int16 OrElse type = DBColumnType.Int32 End Function

                                The implementation of the method is quite simple. The method simply iterates through the DBTable.Columns collection, and adds a persistent property to metadata based on each DBColumn instance. The key property is generated separately, to check some necessary conditions. For example, it is impossible to create runtime metadata mapped to a table with a compound key.

                                XPDictionary can be passed as a parameter to the constructors of the SimpleDataLayer and ThreadSafeDataLayer classes.

                                XPClassInfo classInfo = session1.GetClassInfo(string.Empty, "Categories"); gridControl1.DataSource = new XPCollection(session1, classInfo);
                                Dim classInfo As XPClassInfo = session1.GetClassInfo(String.Empty, "Categories") gridControl1.DataSource = New XPCollection(session1, classInfo)

                                See Also:
                                How to create an XPClassInfo descendant to dynamically build a persistent class structure
                                How to generate persistent classes at runtime based on a dataset
                                How to create collection properties with associations at runtime
                                How to dynamically create a read-only calculated (persistent alias) property
                                How to create persistent classes mapped to tables with a composite primary key at runtime
                                eXpressApp Framework > Concepts > Business Model Design > Types Info Subsystem > Customize Business Object's Metadata