Skip to main content
A newer version of this page is available. .
.NET Framework 4.5.2+

How to: Store the Application Model Differences in the Database

  • 6 minutes to read

When you create a new application with the Security System enabled in the Solution Wizard, the end-user settings (model differences) are stored in the database using the ModelDifferenceDbStore storage, by default. This topic describes how to enable this feature in an existing application, along with how to store shared model differences (administrator’s settings) in the database.

Note

The System.Security.Principal.WindowsIdentity.GetCurrent().Name value is used as a user identifier (passed to the IModelDifference.UserId property) when the Security System is disabled. So, you can enable ModelDifferenceDbStore for WinForms applications with the disabled Security System using the approach described here. However, it is not recommended that you enable ModelDifferenceDbStore for unsecured ASP.NET Web Forms applications, because the UserID will be the same for all users in this instance. Shared model differences are supported for WinForms, ASP.NET Web Forms, and ASP.NET Core Blazor when the Security System is disabled.

Edit the WinModule.cs (WinModule.vb) file located in the WinForms module project. In the overridden ModuleBase.Setup method, subscribe to the XafApplication.CreateCustomModelDifferenceStore and XafApplication.CreateCustomUserModelDifferenceStore events. In these event handlers, pass the ModelDifferenceDbStore instance to the e.Store parameter. Pass the ModelDifference type to the ModelDifferenceDbStore constructor. Here, the ModelDifference is a built-in persistent object from the DevExpress.Persistent.BaseImpl namespace (for XPO) or from the DevExpress.Persistent.BaseImpl.EF namespace (for Entity Framework) implementing the IModelDifference interface. Note the constructor’s contextId last parameter (used to initialize the IModelDifference.ContextId property). In the WinForms module, set it to “Win” to distinguish model differences created for the same user in different platforms.

public sealed partial class MySolutionWindowsFormsModule : ModuleBase {
    private void Application_CreateCustomModelDifferenceStore(Object sender, CreateCustomModelDifferenceStoreEventArgs e) {
        e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), true, "Win");
        e.Handled = true;
    }
    private void Application_CreateCustomUserModelDifferenceStore(Object sender, CreateCustomModelDifferenceStoreEventArgs e) {
        e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), false, "Win");
        e.Handled = true;
    }
    //...
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.CreateCustomModelDifferenceStore += Application_CreateCustomModelDifferenceStore;
        application.CreateCustomUserModelDifferenceStore += Application_CreateCustomUserModelDifferenceStore;
    }
}

Edit the WebModule.cs (WebModule.vb) file located in the ASP.NET Web Forms module project, but set the contextId parameter to “Web” instead of “Win”.

public sealed partial class MySolutionAspNetModule : ModuleBase {
    private void Application_CreateCustomModelDifferenceStore(Object sender, CreateCustomModelDifferenceStoreEventArgs e) {
        e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), true, "Web");
        e.Handled = true;
    }
    private void Application_CreateCustomUserModelDifferenceStore(Object sender, CreateCustomModelDifferenceStoreEventArgs e) {
        e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), false, "Web");
        e.Handled = true;
    }
    // ...
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.CreateCustomModelDifferenceStore += Application_CreateCustomModelDifferenceStore;
        application.CreateCustomUserModelDifferenceStore += Application_CreateCustomUserModelDifferenceStore;
    }
}

Edit the BlazorModule.cs file located in the ASP.NET Core Blazor module project, but set the contextId parameter to “Blazor” instead of “Win”.

public sealed partial class MySolutionBlazorModule : ModuleBase {
    private void Application_CreateCustomModelDifferenceStore(Object sender, CreateCustomModelDifferenceStoreEventArgs e) {
        e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), true, "Blazor");
        e.Handled = true;
    }
    private void Application_CreateCustomUserModelDifferenceStore(Object sender, CreateCustomModelDifferenceStoreEventArgs e) {
        e.Store = new ModelDifferenceDbStore((XafApplication)sender, typeof(ModelDifference), false, "Blazor");
        e.Handled = true;
    }

    // ...
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.CreateCustomModelDifferenceStore += Application_CreateCustomModelDifferenceStore;
        application.CreateCustomUserModelDifferenceStore += Application_CreateCustomUserModelDifferenceStore;
    }
}

Note

When the CreateCustomModelDifferenceStore event is handled, the shared model differences (administrator settings) are stored in the database. Changes with the Model.xafml file located in the application project are ignored if the database record already exists for the shared model differences. To reload settings from Model.xafml, enable the administrative UI and use the Import Shared Model Difference Action (or delete the “Shared Model Difference” record and restart). If this behavior is inappropriate, do not handle this event. Handle it in the RELEASE project configuration only.

Open the Module.cs file and add the following code to the Module constructor:

using DevExpress.Persistent.BaseImpl;
// ...
namespace SimpleProjectManager.Module {
    public sealed partial class SimpleProjectManagerModule : ModuleBase {
        public SimpleProjectManagerModule() {
            // ...
            AdditionalExportedTypes.Add(typeof(ModelDifference));
            AdditionalExportedTypes.Add(typeof(ModelDifferenceAspect));
        }
    }
}

If you use the Entity Framework, additionally register the ModelDifference and ModelDifferenceAspect entity types within your DbContext.

using DevExpress.Persistent.BaseImpl.EF;
// ...
public class MyDbContext : DbContext {
    // ...
    public DbSet<ModelDifference> ModelDifferences { get; set; }
    public DbSet<ModelDifferenceAspect> ModelDifferenceAspects { get; set; }
}

Ensure that all users have read/write access to ModelDifference and ModelDifferenceAspect types.

public class Updater : ModuleUpdater {
    public override void UpdateDatabaseAfterUpdateSchema() {
        base.UpdateDatabaseAfterUpdateSchema();

        PermissionPolicyRole defaultRole = ObjectSpace.FirstOrDefault<PermissionPolicyRole>(role => role.Name == "Default");
        if(defaultRole == null) {
            defaultRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
            defaultRole.Name = "Default";
            defaultRole.AddObjectPermissionFromLambda<PermissionPolicyUser>(SecurityOperations.Read, u => u.Oid == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow);
            defaultRole.AddNavigationPermission(@"Application/NavigationItems/Items/Default/Items/MyDetails", SecurityPermissionState.Allow);
            defaultRole.AddMemberPermissionFromLambda<PermissionPolicyUser>(SecurityOperations.Write, "ChangePasswordOnFirstLogon", u => u.Oid == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow);
            defaultRole.AddMemberPermissionFromLambda<PermissionPolicyUser>(SecurityOperations.Write, "StoredPassword", u => u.Oid == (Guid)CurrentUserIdOperator.CurrentUserId(), SecurityPermissionState.Allow);
            defaultRole.AddTypePermissionsRecursively<PermissionPolicyRole>(SecurityOperations.Read, SecurityPermissionState.Deny);
            defaultRole.AddTypePermissionsRecursively<ModelDifference>(SecurityOperations.ReadWriteAccess, SecurityPermissionState.Allow);
            defaultRole.AddTypePermissionsRecursively<ModelDifferenceAspect>(SecurityOperations.ReadWriteAccess, SecurityPermissionState.Allow);
            // The 'Create' permission is additionally required if you use the Middle Tier Application Server
            defaultRole.AddTypePermissionsRecursively<ModelDifference>(SecurityOperations.Create, SecurityPermissionState.Allow);
            defaultRole.AddTypePermissionsRecursively<ModelDifferenceAspect>(SecurityOperations.Create, SecurityPermissionState.Allow);                
        }
        sampleUser.Roles.Add(defaultRole);
        // ...
        ObjectSpace.CommitChanges();
    }
    // ...
}

Tip

Refer to the How to: Enable the Administrative UI for managing Users’ Model Differences topic to learn how to enable UI elements for managing Model Differences stored in the database.

Note

The following combination of features is not supported when used together.

In this configuration, your application loads information on custom persistent fields from the database and then updates the database schema. However, a thread-safe data layer does not support altering the data model after the database connection is established.