Developing blog project based on ABP vNext and. Net core – data access and code priority

Time:2021-4-18

A series of articles

  1. Developing blog project based on ABP vNext and. Net core
  2. Developing blog project based on ABP vNext and. Net core
  3. Development of blog project based on ABP vNext and. Net core
  4. Developing blog project based on ABP vNext and. Net core – data access and code priority
  5. Developing blog project based on ABP vNext and. Net core
  6. Develop blog project based on ABP vNext and. Net core – unified specification API, packaging return model
  7. Based on ABP vNext and. Net core development blog project swagger, grouping, description, small green lock
  8. Develop blog project based on ABP vNext and. Net core – access GitHub and protect your API with JWT
  9. Developing blog project based on ABP vNext and. Net core – exception handling and logging
  10. Developing blog project based on ABP vNext and. Net core – using redis to cache data
  11. Developing blog project based on ABP vNext and. Net core – integrating hangfire to realize timing task processing
  12. Developing blog project based on ABP vNext and. Net core
  13. Blog project based on ABP vNext and. Net core
  14. Blog project based on ABP vNext and. Net core
  15. Blog project based on ABP vNext and. Net core
  16. Blog project based on ABP vNext and. Net core
  17. Blog project based on ABP vNext and. Net core
  18. Blog project based on ABP vNext and. Net core
  19. Developing blog project based on ABP vNext and. Net core
  20. Blog project based on ABP vNext and. Net core
  21. Blog project based on ABP vNext and. Net core
  22. Blog development project based on ABP vNext and. Net core – blazor series (2)
  23. Blog development project based on ABP vNext and. Net core – blazor series (3)
  24. Blog development project based on ABP vNext and. Net core – blazor series (4)
  25. Blog development project based on ABP vNext and. Net core – blazor series (5)
  26. Blog development project based on ABP vNext and. Net core – blazor series (6)
  27. Blog development project based on ABP vNext and. Net core – blazor series (7)
  28. Blog development project based on ABP vNext and. Net core – blazor series (8)
  29. Blog development project based on ABP vNext and. Net core – blazor series (9)
  30. Developing blog project based on ABP vNext and. Net core

Last article( https://www.cnblogs.com/meowv/p/12909558.html )Perfect the code in the project, access to swagger. This article mainly uses the Entity Framework core to access the database, and uses the code first method for data migration to automatically create the table structure.

data access

stay.EntityFrameworkCoreAdd our data access context object to the projectMeowvBlogDbContext, inherited fromAbpDbContext. And then rewrite itOnModelCreatingmethod.

OnModelCreating: define EF core entity mapping. Call firstbase.OnModelCreatingLet the ABP framework implement the basic mapping for us and then call it.builder.Configure()Extend methods to configure the application’s entities. Of course, it can also be written directly in it without expansion. Such a big lump just doesn’t look good.

In the ABP framework, you can use the[ConnectionStringName]Attribute to configure the connection string name for our dbcontext. Add it first, then add it inappsettings.jsonBecause multiple databases have been integrated before, we also configure multiple connection strings to correspond to them.

This project uses MySQL by default, you can choose whatever you like.

//MeowvBlogDbContext.cs
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;

namespace Meowv.Blog.EntityFrameworkCore
{
    [ConnectionStringName("MySql")]
    public class MeowvBlogDbContext : AbpDbContext
    {
        public MeowvBlogDbContext(DbContextOptions options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Configure();
        }
    }
}
//appsettings.json
{
  "ConnectionStrings": {
    "Enable": "MySQL",
    "MySql": "Server=localhost;User Id=root;Password=123456;Database=meowv_blog_tutorial",
    "SqlServer": "",
    "PostgreSql": "",
    "Sqlite": ""
  }
}

Then create a new extension classMeowvBlogDbContextModelCreatingExtensions.csAnd extension methodConfigure(). Note that the extension method is static and needs to be addedstatic

//MeowvBlogDbContextModelCreatingExtensions.cs
using Microsoft.EntityFrameworkCore;
using Volo.Abp;

namespace Meowv.Blog.EntityFrameworkCore
{
    public static class MeowvBlogDbContextModelCreatingExtensions
    {
        public static void Configure(this ModelBuilder builder)
        {
            Check.NotNull(builder, nameof(builder));
            ...
        }
    }
}

After completing the above operation, in our module classMeowvBlogFrameworkCoreModuleRegister dbcontext to dependency injection, and use different databases according to your configured values. stay.DomainLayer to create a profile access classAppSettings.cs

//AppSettings.cs
using Microsoft.Extensions.Configuration;
using System.IO;

namespace Meowv.Blog.Domain.Configurations
{
    /// 
    ///  appsettings.json Configuration file data reading class
    /// 
    public class AppSettings
    {
        /// 
        ///The root node of the configuration file
        /// 
        private static readonly IConfigurationRoot _config;

        /// 
        /// Constructor
        /// 
        static AppSettings()
        {
            //Loading appsettings.json And build iconfiguration root
            var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
                                                    .AddJsonFile("appsettings.json", true, true);
            _config = builder.Build();
        }

        /// 
        /// EnableDb
        /// 
        public static string EnableDb => _config["ConnectionStrings:Enable"];

        /// 
        /// ConnectionStrings
        /// 
        public static string ConnectionStrings => _config.GetConnectionString(EnableDb);
    }
}

It’s easy to get the content of the configuration file, and it’s easy to understand the comments in the code.

It is worth mentioning that ABP will automatically create a default repository for the entities in dbcontext. You need to add it with options when registeringAddDefaultRepositories()

By default, a warehouse is created for each entity. If you want to create a warehouse for other entities, you canincludeAllEntitiesSet to true, and then you can inject and use it in the serviceIRepositoryorIQueryableRepository

//MeowvBlogFrameworkCoreModule.cs
using Meowv.Blog.Domain;
using Meowv.Blog.Domain.Configurations;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.MySQL;
using Volo.Abp.EntityFrameworkCore.PostgreSql;
using Volo.Abp.EntityFrameworkCore.Sqlite;
using Volo.Abp.EntityFrameworkCore.SqlServer;
using Volo.Abp.Modularity;

namespace Meowv.Blog.EntityFrameworkCore
{
    [DependsOn(
        typeof(MeowvBlogDomainModule),
        typeof(AbpEntityFrameworkCoreModule),
        typeof(AbpEntityFrameworkCoreMySQLModule),
        typeof(AbpEntityFrameworkCoreSqlServerModule),
        typeof(AbpEntityFrameworkCorePostgreSqlModule),
        typeof(AbpEntityFrameworkCoreSqliteModule)
    )]
    public class MeowvBlogFrameworkCoreModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.AddAbpDbContext(options =>
            {
                options.AddDefaultRepositories(includeAllEntities: true);
            });

            Configure(options =>
            {
                switch (AppSettings.EnableDb)
                {
                    case "MySQL":
                        options.UseMySQL();
                        break;
                    case "SqlServer":
                        options.UseSqlServer();
                        break;
                    case "PostgreSql":
                        options.UsePostgreSql();
                        break;
                    case "Sqlite":
                        options.UseSqlite();
                        break;
                    default:
                        options.UseMySQL();
                        break;
                }
            });
        }
    }
}

Now we can design a blog. The required tables are: posts, categories, tags and posts_ Tags, friendlinks

stay.DomainLayer to write entity classes, Post.cs 、 Category.cs 、 Tag.cs 、 PostTag.cs 、 FriendLink.cs . Set the primary key to int type and inherit the entity directly. You can refer to the ABP document for this, https://docs.abp.io/zh-Hans/abp/latest/Entities

Click to view the code
//Post.cs
using System;
using Volo.Abp.Domain.Entities;

namespace Meowv.Blog.Domain.Blog
{
    /// 
    /// Post
    /// 
    public class Post : Entity
    {
        /// 
        ///Title
        /// 
        public string Title { get; set; }

        /// 
        ///Author
        /// 
        public string Author { get; set; }

        /// 
        ///Links
        /// 
        public string Url { get; set; }

        /// 
        /// HTML
        /// 
        public string Html { get; set; }

        /// 
        /// Markdown
        /// 
        public string Markdown { get; set; }

        /// 
        ///Category ID
        /// 
        public int CategoryId { get; set; }

        /// 
        ///Creation time
        /// 
        public DateTime CreationTime { get; set; }
    }
}
//Category.cs
using Volo.Abp.Domain.Entities;

namespace Meowv.Blog.Domain.Blog
{
    /// 
    /// Category
    /// 
    public class Category : Entity
    {
        /// 
        ///Classification name
        /// 
        public string CategoryName { get; set; }

        /// 
        ///Exhibition name
        /// 
        public string DisplayName { get; set; }
    }
}
//Tag.cs
using Volo.Abp.Domain.Entities;

namespace Meowv.Blog.Domain.Blog
{
    /// 
    /// Tag
    /// 
    public class Tag : Entity
    {
        /// 
        ///Label name
        /// 
        public string TagName { get; set; }

        /// 
        ///Exhibition name
        /// 
        public string DisplayName { get; set; }
    }
}
//PostTag.cs
using Volo.Abp.Domain.Entities;

namespace Meowv.Blog.Domain.Blog
{
    /// 
    /// PostTag
    /// 
    public class PostTag : Entity
    {
        /// 
        ///Article ID
        /// 
        public int PostId { get; set; }

        /// 
        ///Tag ID
        /// 
        public int TagId { get; set; }
    }
}
//FriendLink.cs
using Volo.Abp.Domain.Entities;

namespace Meowv.Blog.Domain.Blog
{
    /// 
    /// FriendLink
    /// 
    public class FriendLink : Entity
    {
        /// 
        ///Title
        /// 
        public string Title { get; set; }

        /// 
        ///Links
        /// 
        public string LinkUrl { get; set; }
    }
}

After creating the entity class, in theMeowvBlogDbContextAdd dbset property

//MeowvBlogDbContext.cs
...
    [ConnectionStringName("MySql")]
    public class MeowvBlogDbContext : AbpDbContext
    {
        public DbSet Posts { get; set; }

        public DbSet Categories { get; set; }

        public DbSet Tags { get; set; }

        public DbSet PostTags { get; set; }

        public DbSet FriendLinks { get; set; }

        ...
    }
...

stay.Domain.SharedLayer add global constant classMeowvBlogConsts.csAnd table name constant classMeowvBlogDbConsts.csLet’s make a constant of table prefix. What I write here ismeowv_You can do whatever you want. The names of the tables that represent us will bemeowv_start. And then in theMeowvBlogDbConstsDefine the table name.

//MeowvBlogConsts.cs
namespace Meowv.Blog.Domain.Shared
{
    /// 
    ///Global constant
    /// 
    public class MeowvBlogConsts
    {
        /// 
        ///Database table prefix
        /// 
        public const string DbTablePrefix = "meowv_";
    }
}
//MeowvBlogDbConsts.cs
namespace Meowv.Blog.Domain.Shared
{
    public class MeowvBlogDbConsts
    {
        public static class DbTableName
        {
            public const string Posts = "Posts";

            public const string Categories = "Categories";

            public const string Tags = "Tags";

            public const string PostTags = "Post_Tags";

            public const string Friendlinks = "Friendlinks";
        }
    }
}

stayConfigure()Method, including table name, field type and length. For the following code is not very clear, you can see Microsoft’s custom code first convention: https://docs.microsoft.com/zh-cn/ef/ef6/modeling/code-first/conventions/custom

//MeowvBlogDbContextModelCreatingExtensions.cs
using Meowv.Blog.Domain.Blog;
using Meowv.Blog.Domain.Shared;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using static Meowv.Blog.Domain.Shared.MeowvBlogDbConsts;

namespace Meowv.Blog.EntityFrameworkCore
{
    public static class MeowvBlogDbContextModelCreatingExtensions
    {
        public static void Configure(this ModelBuilder builder)
        {
            Check.NotNull(builder, nameof(builder));

            builder.Entity(b =>
            {
                b.ToTable(MeowvBlogConsts.DbTablePrefix + DbTableName.Posts);
                b.HasKey(x => x.Id);
                b.Property(x => x.Title).HasMaxLength(200).IsRequired();
                b.Property(x => x.Author).HasMaxLength(10);
                b.Property(x => x.Url).HasMaxLength(100).IsRequired();
                b.Property(x => x.Html).HasColumnType("longtext").IsRequired();
                b.Property(x => x.Markdown).HasColumnType("longtext").IsRequired();
                b.Property(x => x.CategoryId).HasColumnType("int");
                b.Property(x => x.CreationTime).HasColumnType("datetime");
            });

            builder.Entity(b =>
            {
                b.ToTable(MeowvBlogConsts.DbTablePrefix + DbTableName.Categories);
                b.HasKey(x => x.Id);
                b.Property(x => x.CategoryName).HasMaxLength(50).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(50).IsRequired();
            });

            builder.Entity(b =>
            {
                b.ToTable(MeowvBlogConsts.DbTablePrefix + DbTableName.Tags);
                b.HasKey(x => x.Id);
                b.Property(x => x.TagName).HasMaxLength(50).IsRequired();
                b.Property(x => x.DisplayName).HasMaxLength(50).IsRequired();
            });

            builder.Entity(b =>
            {
                b.ToTable(MeowvBlogConsts.DbTablePrefix + DbTableName.PostTags);
                b.HasKey(x => x.Id);
                b.Property(x => x.PostId).HasColumnType("int").IsRequired();
                b.Property(x => x.TagId).HasColumnType("int").IsRequired();
            });

            builder.Entity(b =>
            {
                b.ToTable(MeowvBlogConsts.DbTablePrefix + DbTableName.Friendlinks);
                b.HasKey(x => x.Id);
                b.Property(x => x.Title).HasMaxLength(20).IsRequired();
                b.Property(x => x.LinkUrl).HasMaxLength(100).IsRequired();
            });
        }
    }
}

At this point, the project level directory is as follows

1

Code first

stay.EntityFrameworkCore.DbMigrationsNew module class inMeowvBlogEntityFrameworkCoreDbMigrationsModule.cs, data migration context access objectMeowvBlogMigrationsDbContext.csAnd a design time DB factory classMeowvBlogMigrationsDbContextFactory.cs

Module class dependencyMeowvBlogFrameworkCoreModuleModules andAbpModule. And inConfigureServicesMethod.

//MeowvBlogEntityFrameworkCoreDbMigrationsModule.cs
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;

namespace Meowv.Blog.EntityFrameworkCore.DbMigrations.EntityFrameworkCore
{
    [DependsOn(
        typeof(MeowvBlogFrameworkCoreModule)
    )]
    public class MeowvBlogEntityFrameworkCoreDbMigrationsModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.AddAbpDbContext();
        }
    }
}

MeowvBlogMigrationsDbContextandMeowvBlogDbContextNo big difference

//MeowvBlogMigrationsDbContext.cs
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;

namespace Meowv.Blog.EntityFrameworkCore.DbMigrations.EntityFrameworkCore
{
    public class MeowvBlogMigrationsDbContext : AbpDbContext
    {
        public MeowvBlogMigrationsDbContext(DbContextOptions options) : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Configure();
        }
    }
}

MeowvBlogMigrationsDbContextFactoryClass is mainly used to use the code first command(Add-MigrationandUpdate-Database …)

Note that we need to set the connection string of the configuration file separately.HttpApi.HostingStratifiedappsettings.jsonCopy a copy to.EntityFrameworkCore.DbMigrationsYou can configure the connection string of any database you use.

//appsettings.json
{
  "ConnectionStrings": {
    "Default": "Server=localhost;User Id=root;Password=123456;Database=meowv_blog"
  }
}
//MeowvBlogMigrationsDbContextFactory.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;

namespace Meowv.Blog.EntityFrameworkCore.DbMigrations.EntityFrameworkCore
{
    public class MeowvBlogMigrationsDbContextFactory : IDesignTimeDbContextFactory
    {
        public MeowvBlogMigrationsDbContext CreateDbContext(string[] args)
        {
            var configuration = BuildConfiguration();

            var builder = new DbContextOptionsBuilder()
                .UseMySql(configuration.GetConnectionString("Default"));

            return new MeowvBlogMigrationsDbContext(builder.Options);
        }

        private static IConfigurationRoot BuildConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

            return builder.Build();
        }
    }
}

It’s almost over here. Default databasemeowv_blog_tutorialIt doesn’t exist. First create an empty database.

2

Then open the package management console in visual studio and.EntityFrameworkCore.DbMigrationsSet as startup project.

3

Type the command:Add-Migration InitialThe error message is as follows:

Add migration: the 'add migration' item cannot be recognized as the name of a cmdlet, function, script file, or runnable program. Check the spelling of the name. If the path is included, make sure the path is correct, and then try again.
Location line: 1 character: 1
+ Add-Migration Initial
+ ~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Add-Migration:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

This is because we have added one package less. In order to use the code first method to migrate data, we must add,Microsoft.EntityFrameworkCore.Tools

Then install directly with the commandInstall-Package Microsoft.EntityFrameworkCore.ToolsBag, try again

4

You can see that it has been successful, and a migrations folder and the corresponding data migration file have been generated

Finally, enter the update command:Update-DatabaseAnd then open the data.

5

Perfect, successfully created the database table, and the name is also what we want, the field type is OK.__efmigrationshistoryThe table is used to record the migration history, which can be ignored. When we want to modify and add table fields or add new tables, we can use this method.

Solution hierarchy table of contents for reference

6

This article uses Entity Framework core to complete data access and code first way to create database tables. Have you learned it?

Open source address: https://github.com/Meowv/Blog/tree/blog_ tutorial