Click here to Skip to main content
15,886,578 members
Articles / All Topics

NopCommerce Demo Widget -2 Part

Rate me:
Please Sign up or sign in to vote.
4.43/5 (4 votes)
22 Oct 2015CPOL3 min read 6.9K   1  
CodeProject Welcome to second post in series of posts: Developing NopCommerce plugin. Till now we already have project ready for working in NopCommerce solution. In prevoius post link we started with creating and preparing project for working in NopCommerce platform.


Welcome to second post in series of posts: Developing NopCommerce plugin.

Till now we already have project ready for working in NopCommerce solution.
In prevoius post link we started with creating and preparing project for working in NopCommerce platform. Project name is Nop.Plugin.Widgets.DemoWidget. This name is standardized and Nop.Plugin.Widgets should be part of project name of every widget type NopCommerce project. Word on end is our project name, in our case DemoWidget.

In this post we will cover data layer. Let’s begin :)

Our demowidget should be very simple. On public side is a widget with just one drop down list. This drop down list will be populated from database. In admin part will be datagrid and infrastructure to add, edit and delete items for our drop down list datasource. In this post we will see how to add table in database, map domain class to database and prepare our plugin for working with database.

In this post, as first step, we will add new folder Domain

Post2Slika1

In this folder we will add new class WidgetDemoRecord.cs

This class should inherit class BaseEntity from Nop.Core namespace.

Code in this clas is:

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nop.Core;

namespace Nop.Plugin.Widgets.DemoWidget.Domain
{
    public class WidgetDemoRecord : BaseEntity
    {
        public WidgetDemoRecord()
        {

        }

        public virtual int WidgetDemoRecordId { get; set; }  //virtual property is for lazy loading user for Entity Framework

        public virtual string WidgetDemoRecordName { get; set; }

    }
}

Here are two properties. It is pretty self explanatory. List of objects of this class will be used as data source for our drop down list.

Post2Slika2

WidgetDemoMap should inherit class EntityTypeConfiguration with generic type WidgetDemoRecord which we want to map.This class actually contains metadata how we should map out WidgetDemoRecord class into database.

namespace Nop.Plugin.Widgets.DemoWidget.Data
{
    public class WidgetDemoMap : EntityTypeConfiguration<WidgetDemoRecord>
    {
        public WidgetDemoMap()
        {
            ToTable("DemoWidget_WidgetDemo"); //Creating table in database with this name
            HasKey(m => m.WidgetDemoRecordId);  // WidgetDemoRecordId is primary key for this class!

            Property(m => m.WidgetDemoRecordName);  // map property to database table
        }
    }
}

Next, we should prepare for working with database. We will working with Fluent API Entity Framework, rather then with annotation.

We are creating now domain mapping class and adding Entity framework reference to our project.
We should reference dll from nopcommerce directory nopCommerce_3.60_Source\packages\EntityFramework.6.1.3\lib\net45, rather then from nudget as we usually do, to avoid conflicts with NopComerce Entity framework version.

We are adding now new folder in our project DATA and add new class file WidgetDemoMap.cs.
Next we should create ContextObject class who will be in charge for our database operations.
ContextObject class is specialized version of Entity Framework DBContext. It inherits DBCOntext and NopCommerce specific interface IDbContext. NopCommerce framework uses interface IDbContext to find plugin context classes and register at startup. Intention of our ContextObject is to work with standard CRUD database operations and to manage relationship between objects(referential integrity between tables).
In DATA folder we are adding new class WidgetDemoObjectContext

Code in this class is:

public class WidgetDemoObjectContext : DbContext, IDbContext
    {
        public WidgetDemoObjectContext(string nameOrConnectionString) : base(nameOrConnectionString)  // we can pass name or connection string to tell DbContext to which database shoul be connected
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new WidgetDemoMap());  //we are passing to modelbuilder our WidgetDemoMap to be sure that our plugin has only tables in our modelBuilder and i our case this is just one table WidgetDemoRecord wihich is described WidgetDemoMap class
            base.OnModelCreating(modelBuilder);
        }

        public string CreateDatabaseInstallationScript()
        {
            return ((IObjectContextAdapter) this).ObjectContext.CreateDatabaseScript();  //creating sql script for tables defined in OnModelCreating method
        }

        public void Install()
        {
           Database.SetInitializer<WidgetDemoObjectContext>(null);
            Database.ExecuteSqlCommand(CreateDatabaseInstallationScript());
            SaveChanges();
        }


        public void Uninstall()
        {
            this.DropPluginTable("DemoWidget_WidgetDemo");
        }

        public new IDbSet<TEntity> Set<TEntity>() where TEntity : Core.BaseEntity
        {
            return base.Set<TEntity>();
        }


        public bool AutoDetectChangesEnabled
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void Detach(object entity)
        {
            throw new NotImplementedException();
        }

        public int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = null, params object[] parameters)
        {
            throw new NotImplementedException();
        }

        public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : Core.BaseEntity, new()
        {
            throw new NotImplementedException();
        }

        public bool ProxyCreationEnabled
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

     

        public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters)
        {
            throw new NotImplementedException();
        }
    }

Next thing we should care about is dependency injection. In nopcommerce is used contructor injection . Autofac actually take care about constructor parameters. Autofac instantiates and manage instance lifecycle.

Autofac will know how to create instance based on rules in class DependencyRegistrar. This class we will create in just a moment.
We should not forget, of course to add autofac dll reference.
Actually, we will need two references:
1. Autofac.dll in folder nopCommerce_3.60_Source\packages\Autofac.3.5.2\lib\net40
2.Autofac.Integration.Mvc in folder nopCommerce_3.60_Source\packages\Autofac.Mvc5.3.3.4\lib\net45

Next we will add new class in out Data Folder called DemoWidgetDependencyRegistrar.cs. It is very important for this class to implement interface IDependencyRegistrar

NopCommerce platform will search through reflection classes which implements this interface and will call Register method.

public class DemoWidgetDependencyRegistrar : IDependencyRegistrar
    {
        private const string CONTEXT_NAME = "nop_object_context_demo_widget";

        public int Order
        {
            get { return 1; }  // in our plugin order is notimportant, this property actually shows in wich order will be register this method if we have more Regiter mwthod in our plugin
        }

        public void Register(Autofac.ContainerBuilder builder, Core.Infrastructure.ITypeFinder typeFinder)
        {
            this.RegisterPluginDataContext<WidgetDemoObjectContext>(builder, CONTEXT_NAME);

            builder.RegisterType<EfRepository<WidgetDemoRecord>>()
                .As<IRepository<WidgetDemoRecord>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT_NAME))
                .InstancePerLifetimeScope();
        }
    }

Code above should say something like : Autofac will everytime when in constructor parameter is WidgetDemoRecord, referenced as IRepository in constructor arguments,autofac will bring instead of this parameter new instance of EFRepository. Because EFRepository class in constructor needs parameter IDBCOntext, autofac will instantiate new instance of our WidgetDemoObjectContext class because of CONTEXT_NAME parameter.
InstancePerLifetimeScope means that we will have just on EFrepository instance through on web request which is good. We will not worry that we have more instances of EFrepository class that is WidgetDemoRecord object

We finished data access arhictecure for our plugin. Our plugin in ready to start!

Project download source code link (3.60 NopCommerce version)Nop.Plugin.Widgets.DemoWidget

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Serbia Serbia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --