DWKit ORM

DWKit uses its own ORM to access data. It's main feature is that you do not need to write classes to work with it, though you can still do it if you like.

How DWKit ORM requests data?

DWKit ORM can use the following entities as metadata source to extract data :

  • Data Model - ORM returns data as dynamic type objects.
  • Mapping Forms and Data - ORM also returns data as dynamic type objects. This is ORM main method in DWKit, as DWKit deals with forms and data.
  • You can use class inherited from DBObject<T> as metadata. This way DWKit ORM works with strongly typed objects.

Which objects are returned by DWKit ORM?

DWKit ORM can work in two modes - dynamic typed and strongly typed. Choice of mode depends on metadata source type (see previous section).

  • In dynamic mode DWKit ORM returns objects of dynamic type - dynamic or DynamicEntity object. Find more about dynamic type in Microsoft documentation. Actually dynamic and DynamicEntity are equivalent to each other, you can easily cast one into another, with data intact.

    List<DynamicEntity> data = await model.GetAsync(filter,order,paging);
    //manipulate as DynamicEntity
    DynamicEntity firstItem = data.First();
    firstItem["Amount"] = firstItem["Amount"] + 10;
    //manipulate as dynamic
    dynamic firstItemDynamic = data.First() as dynamic;
    firstItemDynamic.Amount = firstItemDynamic.Amount + 10;

    Depending on your tasks and preferences you can use both methods.

  • In strongly typed mode you first describe your business objects as classes inherited from DBObject<T> and then use them to request data and as objects containing data.

    public class BusinessEntity : DbObject<BusinessEntity>
    {
      [DbObjectModel(IsKey = true)]
      public Guid Id
      {
              get => _entity.Id;
              set => _entity.Id = value;
      }
      [DbObjectModel]
      public string Name
      {
          get => _entity.Name;
          set => _entity.Name = value;
      }
    }
    
    List<BusinessEntity> data  = await BusinessEntity.SelectAsync(filter,order)

We recommend to use dynamic mode in most cases. As for strongly typed mode, it should only be used to organize code with complex business logic.

Which object you will deal with when using DWKit ORM?

  • EntityModel class extension methods are usually used to request dynamic typed data, however you'll need to get this model first. Use MetadataToModelConverter class and its static methods to do that. See example below for a model to request form data:

    EntityModel model = await MetadataToModelConverter.GetEntityModelByFormAsync("FormName");
  • When we have EntityModel, we can use it to work with data. For example, to get data from database, change amount for the first item and save changes.

    List<DynamicEntity> data = await model.GetAsync(filter,order,paging);
    dynamic firstItemDynamic = data.First() as dynamic;
    firstItemDynamic.Amount = firstItemDynamic.Amount + 10;
    await model.UpdateAsync(data);
  • Example above is not very efficient, as we can see that data here is requested twice - first when calling GetAsync, and then inside UpdateAsync to get data to compare it with changed data and create requests to database. You can use this approach only if there's a large time gap between requesting and saving data. For example, when data is requested to be displayed in from, then changed in form, and changes are sent to server. You can use ObservableEntityContainer class to write business logic. This class tracks objects changes and creates requests to database. Let's re-write example above using ObservableEntityContainer.

    ObservableEntityContainer container = await DynamicRepository.GetObservableEntitiesAsync(model,filter);
    IEnumeralble<DynamicEntity> data = container.Entities;
    dynamic firstItemDynamic = data.First() as dynamic;
    firstItemDynamic.Amount = firstItemDynamic.Amount + 10;
    await container.ApplyAsync();
  • Also, if you need strongly typed objects, you can use inheriting from DBObject<T> class.
  • SharedTransaction to organize transactions.

Does DWKit ORM support transactions?

Yes, it does. You can open transaction, perform any operations in it via DWKit ORM and then commit it. You need to explicitly open and commit transaction. If it's not committed, it will rollback. All operations performed via DWKit ORM automatically use opened transaction, if they are performed after it was opened and before it is completed.

using (var shared = new SharedTransaction())
{
    await shared.BeginTransactionAsync();
    //any DWKit ORM operations
    await shared.CommitAsync();
}

You're constantly writing await. I am using synchronous code. How do I use your ORM?

We recommend using asynchronous operation to access database, especially from ASP.NET MVC in which you can write asynchronous methods in controllers. However, any asynchronous method can be called from the synchronous method, without having to re-write the latter. See examples of such calls in this article.

Why don't you use another ORM, such as Entity Framework?

Entity Framework is a amazing ORM. But when we were writing DWKit, we had a very specific task - we needed ORM which would allow us get objects of dynamic types, as we wanted to create a system which requires as little code writing, as possible. That is why it was wiser to write our own quite simple ORM which fully fulfils DWKit core needs. Later we found out that we can easily extend this ORM and add new features to it, such as extension attributes or working with calculated columns.

Can we use another ORM (Entity Framework for example) with DWKit?

Yes, you can take any ORM you like using it in server actions, to organize complex business logic. However in our experience this is unnecessary as DWKit ORM is 100% enough to fulfil any goals.

Database support

At the moment DWKit ORM supports MSSQL, PostgreSQL and Oracle.

DWKit ORM distinctive features

  • Mapping data into dynamic type without describing business objects as classes.
  • Strongly typed mapping if required.
  • Extension attributes support.