Define the Data Model and Set the Initial Data

  • 15 min to read

This topic describes how to define the business model and the business logic for WinForms and ASP.NET applications. The applications' business model contains two logical parts that are implemented via different ORM tools:

Logical part ORM tool Classes
Marketing Entity Framework (EF) Customer and Testimonial
Planning eXpress Persistent Objects (XPO) Project and Task

Add the Customer and Testimonial entities (EF)

  1. In the Solution Explorer, right-click the SimpleProjectManager.Module\BusinessObjects folder and select Add | Class… from the context menu. Set the name to "Marketing" and click Add.

  2. Replace the auto-generated file content with the following code:

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Runtime.CompilerServices;
    using DevExpress.ExpressApp.DC;
    using DevExpress.Persistent.Base;
    
    namespace SimpleProjectManager.Module.BusinessObjects.Marketing {
        [NavigationItem("Marketing")]
        public class Customer : INotifyPropertyChanged {
            public Customer() {
                testimonials = new List<Testimonial>();
            }
            int id;
            [Browsable(false)]
            public int Id {
                get { return id; }
                protected set { SetProperty(ref id, value); }
            }
            string firstName;
            public string FirstName {
                get { return firstName; }
                set { SetProperty(ref firstName, value); }
            }
            string lastName;
            public string LastName {
                get { return lastName; }
                set { SetProperty(ref lastName, value); }
            }
            string email;
            public string Email {
                get { return email; }
                set { SetProperty(ref email, value); }
            }
            string company;
            public string Company {
                get { return company; }
                set { SetProperty(ref company, value); }
            }
            string occupation;
            public string Occupation {
                get { return occupation; }
                set { SetProperty(ref occupation, value); }
            }
            List<Testimonial> testimonials;
            [Aggregated]
            public virtual List<Testimonial> Testimonials {
                get { return testimonials; }
                set { SetProperty(ref testimonials, value); }
            }
            [NotMapped]
            public string FullName {
                get {
                    string namePart = string.Format("{0} {1}", FirstName, LastName);
                    return Company != null ? string.Format("{0} ({1})", namePart, Company) : namePart;
                }
            }
            byte[] photo;
            [ImageEditor(ListViewImageEditorCustomHeight = 75, DetailViewImageEditorFixedHeight = 150)]
            public byte[] Photo {
                get { return photo; }
                set { SetProperty(ref photo, value); }
            }
            protected void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null) {
                if (!EqualityComparer<T>.Default.Equals(field, value)) {
                    field = value;
                    OnPropertyChanged(propertyName);
                }
            }
        #region the INotifyPropertyChanged members
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged(string propertyName) {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        #endregion
        }
    }
    
    Show the API description

    API

    Description

    NavigationItemAttribute

    Places a navigation item automatically created for the decorated class in the specified navigation group.

    AggregatedAttribute

    Specifies that the decorated property is an aggregated part of an association.

    ImageEditorAttribute

    Specifies the width and high of the editor that displays an image property.

    FieldSizeAttribute

    Specifies the maximum number of characters that the decorated member's editor can contain.

    VisibleInListViewAttribute

    Shows or hides a column with the decorated property's values in an initial List View.

    NotMappedAttribute

    Specifies that the decorated property should not be mapped to a database.

  3. Open the SimpleProjectManagerDbContext.cs (SimpleProjectManagerDbContext.vb) file within the SimpleProjectManager.Module\BusinessObjects folder. Add the Customer and Testimonial properties to the SimpleProjectManagerDbContext class to register Customer and Testimonial entities within the DbContext as shown below:

    using SimpleProjectManager.Module.BusinessObjects.Marketing;
    
    namespace  SimpleProjectManager.Module.BusinessObjects {
        public class SimpleProjectManagerDbContext : DbContext {
            //... 
            public DbSet<Customer> Customer { get; set; }
            public DbSet<Testimonial> Testimonial { get; set; }
        }
    }
    
  4. In the Solution Explorer, navigate to the Module.cs (Module.vb) file and press the F7 key to open the file in the code editor. Uncomment the #if and #endif directives and code between them as shown below to specify the database initializer for EF. With this uncommented code, the database is recreated each time you change your entities.

    public sealed partial class SimpleProjectManagerModule : ModuleBase {
        static SimpleProjectManagerModule() {
            // ...
            // Uncomment this code to delete and recreate the database each time the data model has changed.
            // Do not use this code in a production environment to avoid data loss.
    #if DEBUG
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<SimpleProjectManagerDbContext>());
    #endif
        }
        // ...
    }
    

Add the Project and ProjectTask persistent classes (XPO)

  1. In the Solution Explorer, right-click the SimpleProjectManager.Module\BusinessObjects folder and select Add | Class… from the context menu. Set the name to "Planning" and click Add.

  2. Replace the auto-generated file content with the following code:

    using System;
    using DevExpress.Persistent.Base;
    using DevExpress.Persistent.BaseImpl;
    using DevExpress.Xpo;
    
    namespace SimpleProjectManager.Module.BusinessObjects.Planning {
        [NavigationItem("Planning")]
        public class ProjectTask : BaseObject {
            public ProjectTask(Session session) : base(session) { }
            string subject;
            [Size(255)]
            public string Subject {
                get { return subject; }
                set { SetPropertyValue(nameof(Subject), ref subject, value); }
            }
            ProjectTaskStatus status;
            public ProjectTaskStatus Status {
                get { return status; }
                set { SetPropertyValue(nameof(Status), ref status, value); }
            }
            Person assignedTo;
            public Person AssignedTo {
                get { return assignedTo; }
                set { SetPropertyValue(nameof(AssignedTo), ref assignedTo, value); }
            }
            DateTime startDate;
            public DateTime StartDate {
                get { return startDate; }
                set { SetPropertyValue(nameof(startDate), ref startDate, value); }
            }
            DateTime endDate;
            public DateTime EndDate {
                get { return endDate; }
                set { SetPropertyValue(nameof(endDate), ref endDate, value); }
            }
            string notes;
            [Size(SizeAttribute.Unlimited)]
            public string Notes {
                get { return notes; }
                set { SetPropertyValue(nameof(Notes), ref notes, value); }
            }
            Project project;
            [Association]
            public Project Project {
                get { return project; }
                set { SetPropertyValue(nameof(Project), ref project, value); }
            }
        }
    }
    
    Show the API description

    API

    Description

    BaseObject

    The base class that provides features for business classes.

    NavigationItemAttribute

    Places a navigation item automatically created for the decorated class in the specified navigation group.

    AssociationAttribute

    Specifies that the decorated property is a part of an association.

    AggregatedAttribute

    Specifies that the decorated property is an aggregated part of an association.

    SizeAttribute

    Specifies the maximum number of characters that the decorated member's editor can contain.

Populate the Database with Initial Data

Open the Updater.cs (Updater.vb) file from the SimpleProjectManager.Module project's Database Update folder and override the ModuleUpdater.UpdateDatabaseAfterUpdateSchema method as shown below:

using DevExpress.Persistent.BaseImpl;
using SimpleProjectManager.Module.BusinessObjects.Marketing;
using SimpleProjectManager.Module.BusinessObjects.Planning;
// ...
public class Updater : ModuleUpdater {
    //...
    public override void UpdateDatabaseAfterUpdateSchema() {
        base.UpdateDatabaseAfterUpdateSchema();
        if (ObjectSpace.CanInstantiate(typeof(Person))) {
            Person person = ObjectSpace.FindObject<Person>(
                CriteriaOperator.Parse("FirstName == ? && LastName == ?", "John", "Nilsen"));
            if (person == null) {
                person = ObjectSpace.CreateObject<Person>();
                person.FirstName = "John";
                person.LastName = "Nilsen";
            }
        }
        if (ObjectSpace.CanInstantiate(typeof(ProjectTask))) {
            ProjectTask task = ObjectSpace.FindObject<ProjectTask>(
                new BinaryOperator("Subject", "TODO: Conditional UI Customization"));
            if (task == null) {
                task = ObjectSpace.CreateObject<ProjectTask>();
                task.Subject = "TODO: Conditional UI Customization";
                task.Status = ProjectTaskStatus.InProgress;
                task.AssignedTo = ObjectSpace.FindObject<Person>(
                    CriteriaOperator.Parse("FirstName == ? && LastName == ?", "John", "Nilsen"));
                task.StartDate = new DateTime(2019, 1, 30);
                task.Notes = "OVERVIEW: http://www.devexpress.com/Products/NET/Application_Framework/features_appearance.xml";
            }
        }
        if (ObjectSpace.CanInstantiate(typeof(Project))) {
            Project project = ObjectSpace.FindObject<Project>(
                new BinaryOperator("Name", "DevExpress XAF Features Overview"));
            if (project == null) {
                project = ObjectSpace.CreateObject<Project>();
                project.Name = "DevExpress XAF Features Overview";
                project.Manager = ObjectSpace.FindObject<Person>(
                    CriteriaOperator.Parse("FirstName == ? && LastName == ?", "John", "Nilsen"));
                project.Tasks.Add(ObjectSpace.FindObject<ProjectTask>(
                    new BinaryOperator("Subject", "TODO: Conditional UI Customization")));
            }
        }
        if (ObjectSpace.CanInstantiate(typeof(Customer))) {
            Customer customer = ObjectSpace.FindObject<Customer>(
                CriteriaOperator.Parse("FirstName == ? && LastName == ?", "Ann", "Devon"));
            if (customer == null) {
                customer = ObjectSpace.CreateObject<Customer>();
                customer.FirstName = "Ann";
                customer.LastName = "Devon";
                customer.Company = "Eastern Connection";
            }
        }
        ObjectSpace.CommitChanges();
    }
    //...
}

In the code above, the Object Space is used to create initial data. This is one of the main framework abstractions that allows you to perform CRUD (create-read-update-delete) operations. You can find more information on the ObjectSpace in the next topic (the Define Custom Logic and UI Elements section).

Note

You can refer to Supply Initial Data (XPO/EF) for more information on how to initially populate the database.

Run the Applications

  • The WinForms Application

    The WinForms project is set as the default startup project. Press Start Debugging or the F5 key to run the application.

    The following image shows the auto-created UI of this application:

    SPM_Win

  • The ASP.NET Application

    Right-click the SimpleProjectManager.Web project in the Solution Explorer and select the Set as StartUp Project item from the context menu. Press Start Debugging or the F5 key.

    The following image shows the auto-created UI of this application:

    SPM_Web

XAF generates this UI for List and Detail Views with available CRUD operations and other capabilities (search, filter, print, etc.). The Detail View contains editors (text box, memo, drop-down box, image and date picker, etc.) that display different business class properties.

Lookup and collection editors display properties that are parts of an association. For example, the Project and ProjectTask classes participate in a One-To-Many relationship. The editor for the "Many" part (the Project's Tasks property) allows users to add, edit, remove, and export tasks.

To display reference properties (the ProjectTask's AssignedTo property), XAF generates a drop-down list of persons in the UI and creates a foreign key that references the Person table in the database. This drop-down list displays person's full names because the FullName property is the default property of the Person class (see Default Property of a Business Class).

Note

You can find more information on UI generation in the List View Column Generation and View Items Layout Generation topics.

Auto-Created Database

The database is automatically created based on your data model. The database columns are generated based on the persistence settings specified in the data model (such as field size set via an attribute). The images below show the Object Explorer window from the SQL Server Management Studio.

SPM_DB

The applications' navigation control contains items for each database table. These navigation items allow a user to navigate to a List View with records and open their Detail Views.

Next topic: Customize the Application UI and Behavior

See Also