• Getting Started
    • Prerequisites
    • Download and Installation
    • Change Log
  • Developer Guide
    • EvenCart Plugins
      • Development Environment Setup
      • Plugin Structure
      • EvenCart MVC
      • Dependency Injection
      • Domain Entities
      • Database Versions
      • Plugin Settings
      • Data Provider Plugin
      • Payment Processing Plugin
      • Shipping Provider Plugin
      • Authentication Provider
      • Widget Plugin
    • EvenCart API
      • Authentication
      • Requests & Responses
      • API EndPoints
    • Caching
  • Designer Guide
    • How to create a theme
    • Extended Tags
      • Layout Tag
      • Widget Tag
      • Json Tag
      • Css Tag
      • Js Tag
      • Bundle Tag
      • Partial Tag
      • Control Tag
      • Route Tag
      • Global Tag
      • Component Tag
    • Extended Filters
    • Global Objects
  • Packaging & Distribution

Creating a data access plugin

A database plugin can perform database operations against EvenCart database to extend default EvenCart software.

Before we create a database plugin, we need to create database versions for our plugin.

The following document describes procedure to create a Database plugin.

Creating the plugin class

A plugin class that inherits EvenCart.Services.Plugins.DatabasePlugin class becomes a database plugin class.

Within the plugin class, we'll need to tell EvenCart about our database versions. To do this, we'll need to override the method GetDatabaseVersions and return the list of database versions that our plugin has.

A database plugin class at the very minimum look like below.

using System.Collections.Generic;
using DotEntity.Versioning;
using EvenCart.Services.Plugins;
using EvenCart.Infrastructure;
using My.Plugin.Versions;

namespace My.Plugin
{
    public class MyDbPlugin : DatabasePlugin
    {
        public override IList<IDatabaseVersion> GetDatabaseVersions()
        {
            var versions = base.GetDatabaseVersions();
            versions.Add(new Version_1_0());
            return versions;
        }
    }
}

In the above example, a thing worth nothing is that the GetDatabaseVersion method first calls it's base class method. This is essential for a database plugin to work correctly.

Creating data access services

Creating data access services in EvenCart is very easy and follows generic inheritance and implementation to reduce the amount of code required to perform database operations.

EvenCart exposes a generic interface called EvenCart.Core.Services.IFoundationEntityService<T> and a generic abstract class EvenCart.Core.Services.FoundationEntityService<T> that implements the interface. The class FoundationEntityService<T> contains full implementation for all the methods. Thus any sub classes automatically implement the same methods.

In order to write data access services, two things are required.

  1. An interface that inherits the interface IFoundationEntityService<T> with the actual domain entity class as it's generic type parameter. We can add more method signatures to this interface as per our requirements.
  2. A class that inherits the class FoundationEntityService<T> with the actual domain entity class as it's generic type parameter and implements the interface created above in step 1.

For example if we need to create data access services for our entity called Book from our domain entities example, we'll have the following interface and classes.

Data Access Interface
using EvenCart.Core.Services;
using My.Plugin.Data;

namespace My.Plugin.Services
{
    public interface IBookService : IFoundationEntityService<Book>
    {

    }
}
Data Access Implementation
using EvenCart.Core.Services;
using My.Plugin.Data;

namespace My.Plugin.Services
{
    public class BookService : FoundationEntityService<Book>, IBookService
    {

    }
}

Note how we pass our domain entity Book as generic type parameter to both the constructs above.

Now we just need to register our service with the dependency container.

...
registrar.Register<IBookService, BookService>();
...

You can read more about dependency injection here. Our service interface IBookService will now be available for resolution within Controllers or anywhere else.

Data access methods

FoundationEntityService<T> implements the following methods.

Method
void Insert(T entity, Transaction transaction = null)
Inserts the entity into the database. If transaction is provided, the query executes within a transaction.
void Insert(T[] entity)
Inserts multiple entities into the database with a single database connection.
void InsertOrUpdate(T entity, Transaction transaction = null)
Inserts or update the provided entity. If the Id column is greater then 0, then an update is performed. Otherwise an insert is performed. If transaction is provided, the query executes within a transaction.
void Update(T entity, Transaction transaction = null)
Updates the database row corresponding to the entity in the database. If transaction is provided, the query executes within a transaction.
void Update(object entity, Expression<Func<T, bool>> where, Transaction transaction, Func<T, bool> action = null)
Updates the columns provided by the object entity based on the where condition. The entity object should be a dynamic object with key-value pairs. If transaction is provided, the query executes within a transaction.
void Delete(T entity, Transaction transaction = null)
Deletes the matching entity from database. If transaction is provided, the query executes within a transaction.
void Delete(Expression<Func<T, bool>> where, Transaction transaction = null)
Deletes the entities matching with where expression. If transaction is provided, the query executes within a transaction.
T Get(int id)
Gets the entity with matching Id column.
IEnumerable<T> Get(Expression<Func<T, bool>> where, int page = 1, int count = int.MaxValue)
Gets all the entities matching with where expression.
IEnumerable<T> Get(out int totalResults, Expression<Func<T, bool>> where, Expression<Func<T, object>> orderBy = null, RowOrder rowOrder = RowOrder.Ascending, int page = 1, int count = int.MaxValue)
Gets all the entities matching with where expression ordered by the orderBy expression. If no orderBy expression is provided, the entities are ordered by primary key.
The out parameter totalResults returns total number rows that match the provided expression.
T FirstOrDefault(Expression<Func<T, bool>> where)

Returns the first entity that matches the where expression. Returns null no rows are found.

IEnumerable<T> Query(string query, object parameters = null)
Returns all the entities from the result of provided query. Use dynamic object to pass the parameter to the query.
int Count(Expression<Func<T, bool>> where = null)
Returns the count of entities that matches the where expression.

As you can see, the methods are similar to those exposed by DotEntity.

Consuming the services

In order to consume the service we can inject the service interface into our controller (or manually resolve the interface as described here if you are working with the service outside the controller).

In the following example, we setup a controller, inject the IBookService and consume the service inside our action method.

public class BooksController : FoundationController
{
    private readonly IBookService _bookService;
    public BooksController(IBookService bookService)
    {
        _bookService = bookService;
    }

    public IActionResult Get(int id)
    {
        var book = _bookService.Get(id);
        return R.Success.With("book", book).Result;
    }
}

The above example fetches the Book with the provided id from the table MARKDOWN_HASHd553e76263385cbb18947c5069239b3bMARKDOWNHASH *(All the table names in EvenCart start with the prefix ec)*

Note however that the virtual property Pages inside book object will be null because the default service doesn't fetch the related entities automatically.

The next section summarizes how we can override default functionality to fetch the data from Page table.

Customizing the services

There are times when default implementations from FoundationService<T> are limiting your queries. Because all the methods are declared as virtual you can always override any of the above methods.

For example, in the BookService above, the default implementation of Get(id) will fetch the Book matching with the provided Id. It however doesn't populate the related entity Page.

To achieve that, we'll override the Get(id) method in our BookService to include a join.

using EvenCart.Core.Services;
using My.Plugin.Data;

namespace My.Plugin.Services
{
    public class BookService : FoundationEntityService<Book>, IBookService
    {
         public override Book Get(int id)
        {
            return Repository.Join<Page>("Id", "BookId", joinType: JoinType.LeftOuter)
                .Relate(RelationTypes.OneToMany<Book, Page>())
                .Where(x => x.Id == id)
                .SelectNested()
                .FirstOrDefault();
        }
    }
}

In the above example, we have provided a new implementation for Get(id) method that fetches linked Page rows. The relate function is used to define the relationship one-to-many from Book to Page.

Note that each Page object also automatically gets it's Book virtual property assigned.

The Repository in the above code is a wrapper around EntitySet<T> from DotEntity library.

ON THIS PAGE
  • Creating the plugin class
  • Creating data access services
  • Data access methods
  • Consuming the services
  • Customizing the services

Related Pages

  • Creating a payment processor plugin
  • Creating a shipping provider
  • Creating an authentication provider plugin
  • Creating a widget plugin
© 2022 Sojatia Infocrafts Pvt. Ltd. All rights reserved. Powered by onlyDoc.