WellFrame is a fullstack software developing framework. It produces out of database definitions (tables, columns, references, indexes) a well defined and complete framework based on the MVC architecture.
The code generation is controlled via templates so that the framework can be generated in several target languages (such as C #, Java) – however the main focus here is C#. The framework components focus are:
– C#, the .Net framework for the data and business layer
– HTML5, CSS3 and Javascript for the presenation layer including windows metro apps.
– Android/iPhone apps, used as phone-gap for the web application.
The framework is based on modern technologies and automatically creates an environment that includes a data and business layer. Based on this layers a Web service (WCF) will be automatically generated, the options of the web service properties can be controlled with the help of meta informations defined by user (see “*-meta.xml” in the downloadable examples here).
For the presentation layer the framework provides basic tools, even thow a complete web development environment in HTML5, CSS3 and Javascript. The web development environment also includes an environment with basic functions to create Android apps and windows metro apps.
The Android app acts as a shell (similar to phone-gaps) to control the Web application and can access features of the Android operating system.
Main Focus in the provided framework is setting up a development environment that provides basic functions for modern software development, without being dependent on additional tools. So own requirements scale better and old projects can be better ported.
The ready-to-use web components and the web environment of the framework make the transition for people without web experience like a self-evident task.
Components
The main function of the Framework is its dynamic and transparent capability, this will only be seen if all the components of the Framwork are used together. For better understanding and illustrating the functionality, the components will be individually presented and illustrated with examples.
Following flow chart illustrates the operation of the Wellcode Framework:
At the end an example including a complete development environment will be posted, which presents all the components togather.
WellFrame.dll
To work with WellFrame, you need the library WellFrame.dll, that includes all the necessary functions enabling working with the framework.
An example can be downloaded here. This example uses the framework WellFrame to reflect/map the person from the Microsoft sample database AdventureWorks and perform some routines on it.
The AdventureWorks database, you can be downloaded from the Microsoft or Codeplex sites here. Otherwise the the person table can be created in any database using the following command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
CREATE TABLE [Person].[Person]( [BusinessEntityID] [int] NOT NULL, [PersonType] [nchar](2) NOT NULL, [NameStyle] [dbo].[NameStyle] NOT NULL CONSTRAINT [DF_Person_NameStyle] DEFAULT ((0)), [Title] [nvarchar](8) NULL, [FirstName] [dbo].[Name] NOT NULL, [MiddleName] [dbo].[Name] NULL, [LastName] [dbo].[Name] NOT NULL, [Suffix] [nvarchar](10) NULL, [EmailPromotion] [int] NOT NULL CONSTRAINT [DF_Person_EmailPromotion] DEFAULT ((0)), [AdditionalContactInfo] [xml](CONTENT [Person].[AdditionalContactInfoSchemaCollection]) NULL, [Demographics] [xml](CONTENT [Person].[IndividualSurveySchemaCollection]) NULL, [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL CONSTRAINT [DF_Person_rowguid] DEFAULT (newid()), [ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_Person_ModifiedDate] DEFAULT (getdate()), CONSTRAINT [PK_Person_BusinessEntityID] PRIMARY KEY CLUSTERED ( [BusinessEntityID] ASC ) ) |
The following steps should be followed in order to integrate WellFrame in your application:
-
-
-
- Download the WellFrame libraries from this link. The DLLs are compiled for AnyCPU.
- Add references in your project on WellFrame.dll, Basics.dll and DbmsLibrary.dll.
- The abstract class EntityManager needs to be derived in the project, using this class Entities could be grouped instantiated, changed, or deleted.
-
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Wellcode.Frame; namespace AdventureWorks { public partial class AdvEntityManager : EntityManager { /// <summary> /// this static instance provides functions for all new generated entities in the class library /// </summary> public static new AdvEntityManager Manager { get { if (EntityManager._Manager == null) EntityManager._Manager = new AdvEntityManager(); return (AdvEntityManager)EntityManager._Manager; } } } } |
Entity
This presents accordingly an object and its properties. In our example, this would be the class Person . The class Person includes properties such as FirstName, LastName, etc. A possible definition can be as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
/// <summary> /// Person / Person - Entity /// </summary> [DataContract] public partial class Person : WebEntity { #region Members /// <summary> /// BusinessEntityId / Person.BusinessEntityID /// </summary> /// <returns>int?</returns> [DataMember] public virtual int? BusinessEntityId { get { return (int?)this["BusinessEntityID"]; } set { this.Add("BusinessEntityID", value, typeof(int?)); } } /// <summary> /// FirstName / Person.FirstName /// </summary> /// <returns>string</returns> [DataMember] public virtual string FirstName { get { return (string)this["FirstName"]; } set { this.Add("FirstName", value, typeof(string)); } } /// <summary> /// LastName / Person.LastName /// </summary> /// <returns>string</returns> [DataMember] public virtual string LastName { get { return (string)this["LastName"]; } set { this.Add("LastName", value, typeof(string)); } } /// etc. #endregion } // Person |
EntityList
This presents a list of Entity. The base class for the listing is WebEntityList. In our example, the class would PersonList and is defined as follows:
1 2 3 4 5 6 7 8 |
/// <summary> /// Person / PersonList - List /// </summary> [DataContract] public partial class PersonList : WebEntityList<Person> { } |
Factory (Controller)
A factory class must be defined for each entity. The factory class contains the business logic and the manipulation of an entity.
The base class for a factory is WebEntityFactory and takes -the meaning according to- two template classes, theentity and its collection.
In our example, the factory class for the person would be PersonFactory. In the Factory diverse functions can be overwritten or added. The definition of the class PersonFactory can look as follows. The definition leans heavily on the primary key in the table Person :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
/// <summary> /// Person - Person - Factory /// </summary> public partial class PersonFactory : WebEntityFactory<Person, PersonList> { /// <summary> /// Factory Intialisierung. /// Tabellenname = Person, /// Felder = "BusinessEntityID" /// Query = ... /// </summary> private PersonFactory(EntityManager manager) { this.Manager = manager; this.TableSchema = "Person"; this.TableName = "Person"; this.Fields = new string[] { "BusinessEntityID" }; this.Query = null; this.Database = DatabaseEnum.Standard; } internal static PersonFactory CreateFactory(EntityManager manager) { return new PersonFactory(manager); } /// <summary> /// Erstellt eine neue instanz zu Person /// </summary> /// <returns>Neue instanz zu Person, falls erfolgreich</returns> public override Person CreateEntity() { var item = new Person(); // Änderungen an den EntityManager melden item.PropertyChanging += this.Manager.WebEntity_PropertyChanging; item.PropertyChanged += this.Manager.WebEntity_PropertyChanged; item.AquireEntityManager += this.Manager.AquireEntityManager; return item; } /// <summary> /// statische Methode für GetEntity /// </summary> /// <returns>Entity, falls vorhanden</returns> public Person GetItem(int? businessEntityId) { return this.GetEntity(0, businessEntityId); } /// <summary> /// statische Methode für GetEntity mit Angabe einer Db-Connection /// </summary> /// <returns>Entity, falls vorhanden</returns> public Person GetItem(DbConnector conn, int? businessEntityId) { return this.GetEntity(conn, 0, businessEntityId); } } |
EntityManager
in an automated environment the EntityManager would be automatically added to several manipulating functions of an entity. In our example, we need to add them now manually:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#region Einträge für EntityManager /* /// <summary> /// AdvEntityManager Teil zu PersonFactory / Person / Person. /// </summary> */ public partial class AdvEntityManager { /// <summary> /// PersonFactory zu Person / Person. /// </summary> public PersonFactory PersonFactory { get { if (_PersonFactory == null) { _PersonFactory = global::AdventureWorks.PersonFactory.CreateFactory(this); // register factory to the entity manager this.Factories.Add(_PersonFactory, typeof(Person)); } return _PersonFactory; } } private PersonFactory _PersonFactory = null; /// <summary> /// GetPerson zu Person / Person /// Holen einer Entity über ihre Primary-Key-Felder /// </summary> /// <returns>Entity, falls vorhanden</returns> public Person GetPerson(int? businessEntityId) { return this.PersonFactory.GetEntity(0, businessEntityId); } /// <summary> /// GetPerson zu Person / Person /// Holen einer Entity über ihre Primary-Key-Felder mit Angabe einer Db /// </summary> /// <returns>Entity, falls vorhanden</returns> public Person GetPerson(DbConnector conn, int? businessEntityId) { return this.PersonFactory.GetEntity(conn, businessEntityId); } /// <summary> /// GetPersonList zu Person / Person /// Eine Liste von Person mit einer Where-Klausel zurückgeben /// </summary> /// <returns>Liste möglicher Entities</returns> public PersonList GetPersonList(SqlWhereClause where) { return this.PersonFactory.GetEntities(where); } /// <summary> /// GetPersonList zu Person / Person /// Gesamten Inhalt von Person zurückgeben /// </summary> /// <returns>Liste möglicher Entities</returns> public PersonList GetPersonList() { var where = new SqlWhereClause(); return this.PersonFactory.GetEntities(where); } /// <summary> /// SavePerson zu Person / Person /// Speichern/Hinzufügen einer Entity /// </summary> /// <returns>Entity, falls vorhanden</returns> public Person SavePerson(Person item) { return this.PersonFactory.SaveEntity(item); } /// <summary> /// SavePerson zu Person / Person /// Speichern/Hinzufügen einer Entity mit Angabe einer Db-Connection /// </summary> /// <returns>Entity, falls vorhanden</returns> public Person SavePerson(DbConnector conn, Person item) { return this.PersonFactory.SaveEntity(conn, item); } /// <summary> /// RemovePerson zu Person / Person /// Delete an entity object /// </summary> /// <returns>true, if removed</returns> public bool RemovePerson(Person item) { return this.PersonFactory.RemoveEntity(item); } /// <summary> /// RemovePerson zu Person / Person /// Delete an entity object /// </summary> /// <returns>true, if removed</returns> public bool RemovePerson(DbConnector conn, Person item) { return this.PersonFactory.RemoveEntity(conn, item); } /// <summary> /// Speichert eine Auflistung von PersonList. /// Als gelöscht markierte Entities werden endgültig gelöscht /// </summary> /// <param name="items"></param> /// <returns></returns> public int SavePersonList(PersonList items) { return this.PersonFactory.SaveEntities(items); } } #endregion |
In summary, two files are created for the classes Entity, EntityList, EntityFactory and EntityManager. The classes themselve must then partially be defined, because the class is defined in two separate files, “*.Designer.cs” and “*.cs“.To see a detailed example using the full framework go to this link.
In our example the following files are created:
- The file Person.Designer.cs includes all properties of Person, such as FirstName , LastName, etc.
In addition, the file contains partial definition for the entity manager EntityManager, such. as creating an instance. - The second file is the so-called custom part and can contain the business logic and some overrides of the basic classes.
Now bringing everything together, so if we want -as example- read all persons, we have to set up a valid connection string to the AdventureWorks database, as follows:
1 |
Data Source=.\SQL2014;Initial Catalog=AdventureWorks2014;Integrated Security=True |
Then all person can be read with the following command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Wellcode.Basics.WelloConfig.Instanz.DbConnection.ConnectionString = "Data Source=.\SQL2014;Initial Catalog=AdventureWorks2014;Integrated Security=True"; // get all persons var persons = AdvEntityManager.Manager.GetPersonList(); foreach(var person in persons) { Console.WriteLine(person.FirstName + " " + person.LastName); } // change a person name persons[0].FirstName = "changed using WillFrame"; // save the changes AdvEntityManager.SavePerson(persons[0]); // another way to save changes AdvEntityManager.SaveAll(); |
The complete example can be downloaded here. It is created with Visual Studio 2013 and .Net Framework 4.5.
to be continued …