Data model structure and object managers

Objects are the main component of ELMA. They are used to define business logic and store configuration data. You can learn basics about ELMA objects in ELMA help.

ELMA is based on .NET platform and it affects the object model most of all:

  • All custom (user-defined) objects are stored in .NET assembly (ELMA.ConfigurationModel);
  • For each object ELMA creates a unique class:
    • For objects, these classes are located in Objects section;
    • For document types these classes are located in Documents section;
    • For business processes, these classes are located in Processes
  • For each object property, ELMA creates a new class property.

Thus, it is easy to use objects in scripts – you only need to use simple classes and their properties. All classes of system objects inherit the IEntity interface. You can learn about it in ELMA API .

/// <summary>
/// The interface object ID
/// </summary>
public interface IIdentified
{
    /// <summary>
    /// Get the untyped value of the object identifier
    /// </summary>
    /// <returns>ID Value</returns>
    object GetId();

    /// <summary>
    /// Determine the untyped value of the identifier
    /// </summary>
    /// <param name="id">ID Value</param>
    void SetId(object id);
}
public interface IEntity : IIdentified
{
    ///<summary>
    /// Returns object string view
    ///</summary>
    ///<param name="format">Display format, the properties are available through{$Property Name}</param>
    ///<returns>A string representing the object</returns>
    string ToString(string format);


    /// <summary>
    /// Get the property value accordng to its UID
    /// </summary>
    /// <param name="propertyUid">Property UID</param>
    /// <returns>Property Value</returns>
    object GetPropertyValue(Guid propertyUid);

    /// <summary>
    /// Get the property value accordng to its UID
    /// </summary>
    /// <typeparam name="T">Property type</typeparam>
    /// <param name="propertyUid">Property UID</param>
    /// <returns>Property Value</returns>
    T GetPropertyValue<T>(Guid propertyUid);

    /// <summary>
    /// Determine the property value accordng to its UID
    /// </summary>
    /// <param name="propertyUid">Property UID</param>
    /// <param name="value">Property Value</param>
    void SetPropertyValue(Guid propertyUid, object value);
    
    /// <summary>
    /// Get property´s settings (return settings for the object´s instance, or a copy of the general settings)
    /// </summary>
    /// <param name="propertyUid">Property UID</param>
    TSettings GetPropertySettings<TSettings>(Guid propertyUid)
        where TSettings : TypeSettings;
    
    /// <summary>
    /// Get property´s settings (return settings for the object´s instance, or a copy of the general settings)
    /// </summary>
    /// <param name="propertyUid">Property UID</param>
    TypeSettings GetPropertySettings(Guid propertyUid);

    /// <summary>
    /// Get property´s settings (return settings for the object´s instance, or a copy of the general settings)
    /// </summary>
    /// <param name="propertyUid">Property UID</param>
    /// <param name="defaultSettings">Default settings</param>
    TypeSettings GetPropertySettings(Guid propertyUid, TypeSettings defaultSettings);

    /// <summary>
    /// Get property´s settings stored for this object. Otherwise return null
    /// </summary>
    /// <param name="propertyUid">Property UID</param>
    TypeSettings LoadPropertyInstanceSettings(Guid propertyUid);

    /// <summary>
    /// Save Property's Settings for the object

    /// </summary>
    /// <param name="propertyUid">Property UID</param>
    /// <param name="settings">Settings</param>
    void SavePropertyInstanceSettings(Guid propertyUid, TypeSettings settings);

    /// <summary>
    /// Download the repository of the property's settings of the object
    /// </summary>
    /// <param name="createIfNotExists">Whether to generate the repository if it does not exist</param>
    /// <returns></returns>
    ITypeSettingsInstanceStore LoadSettingsInstanceStore(bool createIfNotExists = false);

    /// <summary>
    /// Get objects contained in this entity (for example, unit items, object´s properties)
    /// </summary>
    /// <returns></returns>
    IEnumerable<IEntity> GetContainedEntities();

    /// <summary>
    /// Get root object (if it is a block item, the first parent returns)
    /// </summary>
    /// <returns></returns>
    IEntity GetRootEntity();

    /// <summary>
    /// Save object
    /// </summary>
    void Save();

    /// <summary>
    /// Delete object
    /// </summary>
    void Delete();

    /// <summary>
    /// Update the object of the DB
    /// </summary>
    void Refresh();

    /// <summary>
    /// Object has not been stored in the database
    /// </summary>
    /// <returns></returns>
    bool IsNew();
}

System objects

ELMA includes numerous pre-configured system objects. They are located in different assemblies and namespaces (according to the structure of the modules). However, you can always find the object you need in ELMA Designer in the Objects section. You can find the information you need to work with the objects in scripts in the Data Structure unit of the Common tab:

When you use system objects in scripts, pay attention to their namespaces.

On the screenshot above, you can see that the User object is located in the ELeWise.Security.Models namespace. It means that you have to use this namespace in scripts:

using EleWise.ELMA.Security.Models;

User objects

In addition to system objects, you can create your own objects in ELMA. These objects will be located in the EleWise.ELMA.ConfigurationModel namespace:

You can find this information for business processes on the Settings tab of a business process page in ELMA Designer:

Note that the class is generated for context variables of the business process and is located in the EleWise.ELMA.Model.Entities.ProcessContext namespace.

In most cases, the namespace with custom models will already be included to the scripts and you can immediately use all your models.

Object managers

To manage objects (e.g. load, save, search) ELMA uses special classes – object managers. You can get a manager for each object, if you know its class. Like ELMA objects, object managers are divided into system and user ones.

All managers inherit the IEntityManager base interface. You can learn about it in ELMA API help.

To facilitate work with typed data, there is also a typed interface of this manager: IEntityManager<T>. You can learn about it in ELMA API help.

For each type of entity that is created using entity editor, ELMA create a base manager:

public class EntityManager<T, IdT> : AbstractNHEntityManager<T, IdT> where T : IEntity<IdT>
{
}

These managers already have a set of methods for working with objects. The main methods are:

//Load an object from database by ID (type of identifier is configured in entity editor)
//If no object with specified ID found, an exception is thrown
public sealed override T Load(IdT id)
 
// Load an object from database by ID (type of identifier is configured in entity editor)
// If no object with specified ID found, null is returned 
public sealed override T LoadOrNull(IdT id)
 
//Save an object to database
public sealed override void Save(T obj)
 
//Save object changes to database
public sealed override void Update(T obj)
 
//Delete an object from database
public sealed override void Delete(T obj)
 
//Delete all objects of this type
public override void DeleteAll()
 
//Reload the object from database (this object is updated in cash too)
public sealed override void Refresh(T obj)
 
//Get all objects of the specified type
public sealed override ICollection<T> FindAll()
 
//Get all objects that meet the filter criteria (this method uses the filter that is generated for this type in entity //editor)
public sealed override ICollection<T> Find(Filter filter, FetchOptions fetchOptions)

How to use managers

To use an object manager, you have to know the class of the object. Suppose, you need to get a manager for the Pet object from the EleWise.ELMA.ConfigurationModel namespace (we created it in ELMA Designer earlier). In this case, invocation of the manager looks like this:

var manager = EleWise.ELMA.Model.Managers.EntityManager<EleWise.ELMA.ConfigurationModel.Pet>.Instance;

However, you can add the namespaces with using, and get the manager with the following code:

var manager = EntityManager<Pet>.Instance;

Here we use the static class EntityManager<T> to get a manager by object type. Generally, there are several ways to get an object manager:

  • Use the static class EntityManager<T>;
  • Use Locator class and get managers as services using the GetServiceNotNull<IEntityManager<T>>() interface;
  • Use Locator class and get managers using the manager’s system class: GetServiceNotNull<UserManager>().

Either way, basic manager functions (loading, searching, saving) will be available. Below is an example of a simple script, where we load pet objects by filter and their properties:

public virtual void TestingManagers (Context context)
		{
			//Get manager for Pet class
            var manager = EntityManager<Pet>.Instance;
            //Create new filter for Pet objects
            var filter = new PetFilter()
            {
                Age = new EleWise.ELMA.Model.Ranges.Int64Range()
                {
                    From = 5
                },
                Kind = new DropDownItem("Cat")
            };
            // Search pets according to the filter criteria
            var pets = manager.Find(filter, null);
            //Change the property of each pet that was found
            foreach (var pet in pets)
            {
                pet.Old = true;
                pet.Save();
            }
		}

To make sure that you can create a filter for objects, you need to enable the Generate Filter option in the object properties. In our case, go to ELMA DesignerObjectsPetAdditional tab – Filter Settings section:

You also need to enable Participates in Search (Filter) option for the properties, that you want to search by (in our case, these properties are Age and Kind). To do that, you need to go to ELMA DesignerObjectsPetPropertiesAge (double click to open Properties) – Advanced Settings:

 

System managers

As it was mentioned above, you can get managers by using a system manager class. In ELMA, there are special managers for most system objects, i.e. separate classes, which extend the basic functions of managers.

For example, UserManager provides additional functions for managing users:

/// <summary>
/// Check if one user is a manager of another user
/// </summary>
/// <param name="cheifUser">Manager</param>
/// <param name="subordinateUser">Subordinate</param>
/// <returns></returns>
public bool IsSubordinateUser([NotNull] Models.IUser cheifUser, [NotNull] Models.IUser subordinateUser)
/// <summary>
/// Check if the user has a manager
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public bool HasChiefForUser([NotNull] Models.IUser user)
/// <summary>
/// Get users assigned to the specified job position (position = organizational structure item). If org. structure element has ‘Job Position’ type, then return the user, assigned to the position
/// If org. structure element has ‘Department’ type, return all employees of the department (including nested positions)
/// </summary>
/// <param name="departament"></param>
/// <returns></returns>
public IEnumerable<Models.IUser> GetUsersByDepartament([NotNull] IOrganizationItem departament)

You can learn more about the methods of UserManager and other managers in ELMA API help.

There is a hint about how to get system managers for objects. If an object’s class is located in the EleWise.ELMA.Security.Models namespace, then the relevant system manager is located in the adjacent namespace EleWise.ELMA.Security.Managers (you just replace Models with Managers).

How to override the base manager

If you want to override a method of the base manager, you need to create a new class and derive it from EntityManager.

For example, we need to encrypt a password and create a new My Documents folder for new users when they are created in ELMA. To do so, we need to override the manager’s method that saves the User objects to database:

public class UserManager : EntityManager<User, long>
        {
            //method for creating the 'My Documents' folder for a user
            private static void CreateFolders (User user)
            {
                if (MyDocumentFolderManager.Instance.LoadByUser(user) == null)
                {
                    MyDocumentFolderManager.Instance.CreateForUser(user);
                }
            }

            //Override the method that saves User objects to database
            protected override void SaveEntity (User obj)
            {
                //If an object is new
                if (obj.Id == 0)
                    //Encrypt password
                    obj.Password = EncryptionHelper.GetMd5Hash(obj.Password);
                //Call the base method that saves the object to database
                base.SaveEntity(obj);
                if (obj.Id > 1)
                    //Create 'My documents' folder (if it does not exist)
                    CreateFolders(obj);
            }
        }

 

See also:

Locator of ELMA services