.net core +codefirst(.net core 基础入门,适合这方面的小白阅读)

 

前言 

 .net core mvc和 .net mvc开发很相似,比如 视图-模型-控制器结构。所以.net mvc开发员很容易入手.net core mvc 。但是两个又有细微的区别,比如配置.net mvc中Web.config和Global.asax消失,而在.net core mvc中则是Startup.cs、Program.cs、appsettings.json等等。所以想要深入了解.net core就必须更加深入的学习。而刚刚开始的学习则是通过建立一个连接数据库的demo开始。由于配置文件的不同,导致很多新手在连接数据库,或者使用codeFisrt开发却不知道怎么配置。所以我在这里较为详细的写一个demo提供给需要此方面的博友。(如有不正确地方欢迎各位指正)

开发工具vs2017

数据库  mssql2014

.net core环境 .net core2.1

1】先建立model层

  1.1先建立一个空白方案

然后建立一个内库,用来存放model:注意选择内库(.net core)

  1.2在model层添加内容

现在nuget中分别引用:Microsoft.EntityFrameworkCore.SqlServer和Microsoft.EntityFrameworkCore.Tools,注意两者版本号最好相同,以免出错

  然后加入model和数据库的上下文类DataBase(这个名字自己随意取),我在这里先只建立一个user表(注意在DataBase中需要

using Microsoft.EntityFrameworkCore;)

public class DataBase : DbContext
    {
        //构造方法
        public DataBase(DbContextOptions<DataBase> options)
            : base(options)
        { }

        #region 数据区域
        public DbSet<User> User { get; set; }
        #endregion

    }

至此,model层配置完毕

2】开始建立.net core项目

先建立一个.net core项目

项目建立完毕之后先引用model层

然后进入Startup.cs配置数据库连接,这里首先引用using Microsoft.EntityFrameworkCore;和model层 using Modelx;然后配置连接

注意services.AddDbContext<DataBase>中的DataBase是model层中的  数据库的上下文类,别弄错了

以上全部完成,然后添加一个例子看看效果,在任意一个控制器中写入以下代码然后运行(.net core 的一个好处就是内置依赖注入)

这时,会发现程序报错

原来,.net core 和.net mvc相比,在使用codefirst时候,除了配置文件之外,.net core 还需要在控制台中执行以下两行代码

 先输入:Add-Migration  MyFirstMigration(名字。这里随意取未MyFirstMigration)

 在输入:Update-Database  

首先我们打开控制台:

先输入:Add-Migration  MyFirstMigration然后回车等待运行完毕

然后输入:Update-Database  回车,等到全部运行完毕之后,再运行项目看看,就发现项目正常运行,以及数据库正常生成

3】ps:关于连接数据库的第二中方法。

关于上文连接数据库,或许有人会问:和自己连接的不太一样,.net core 连接字符串不是应该写在appsettings.json里面?下面,我就将连接数据库的第二种方法写在下面,毕竟多多益善

如果想尝试这种方法的话,别忘了在控制台输入

先输入:Add-Migration MyFirstMigrations(名字,为了和上面区分,这里加了s)

在输入:Update-Database

【我们一起写框架】领域驱动设计的CodeFirst框架(一)—序篇

 

前言

领域驱动设计,其实已经是一个很古老的概念了,但它的复杂度依旧让学习的人头疼不已。

互联网关于领域驱动的文章有很多,每一篇写的都很好,理解领域驱动设计的人都看的懂。

不过,这些文章对于那些初学者而言,还是如同天书一样。

买本驱动领域的书来看?别逗了,这可不是C#语法入门,哪里有书能写明白的。

想学会领域驱动设计,只有一途——实践,不断的实践。

领域驱动设计是什么?

领域驱动设计就是我们俗称的DDD,英文全拼是Domain-Driven Design。

我认为,理解领域驱动设计的第一步是,顾名思义;所以,让我们先直白的通过名字来解释看看。

领域驱动设计:用业务领域来做模块分割,以领域为核心思想设计框架,用设计好的领域来驱动系统实现。

如何?这样是不是就好理解了。

其实,领域驱动设计,和我们之前常用的模型驱动设计很相似。其核心区别,也就是一个聚合的概念。

虽然,现在看来,CodeFirst中的聚合太普遍了,但早在十几年前,聚合可是一个让我们头疼的难题,因为那个时代还没有CodeFirst这么便捷的框架。

什么?你不知道聚合是什么?

别担心,我们在后续实现框架的地方,结合代码把这些聚合啦,值对象啦,等等名词一一讲解。

其实,以现在的技术框架的成熟度,聚合这种东西,不理解也就不理解了,无所谓的。

领域驱动设计的意义

虽然,我不想把领域驱动设计搞的那么神秘,但,事实上,领域驱动设计确实挺难学的。

虽然,我们有了CodeFirst这样优秀的框架,但那只是针对使用者,而对设计者而言,CodeFirst并没有减少设计逻辑。所以,想学会领域驱动设计,还是要有一点耐心,并花一点时间,付诸于实践。

虽然,领域驱动设计很复杂,但,我认为它是值得我们付出时间和心血学习的。

因为,驱动领域设计是技术思维的一个分水岭,学会了这种技术思维后,会对框架设计的理解更上一个台阶。

那么,让我们一起做一个领域驱动的框架,在实践中领会这门技艺吧。

领域驱动设计的实现

我们即将编写的框架是基于Entity Framework的,所以越熟悉Entity Framework越好,如果你不熟悉EF,那也没关系,因为我们是从头一步一步编写的。

下面让我们一起编写框架吧。

首先,我们创建项目如下:

接下来我们把相关的DLL放到KibaDDD程序集下待用。

然后我们编写核心代码程序集Repository。

首先为Repository程序集引入外部DLL[EntityFramework,EntityFramework.Extended,EntityFramework.SqlServer,CodeFirstStoredProcs],同时,再为程序集引入Utility程序集。

然后我们开始设计Repository程序集的布局。

如上图所示,我们建立了Repository程序集的布局,布局中的文件夹及文件作用如下:

TableMapping文件夹:用于存储数据表的映射关系。

TableModel文件夹:用于存储数据表模型。

TableRepository文件夹:用于操作数据表。

DateBaseContext文件:管理数据库的核心文件。

RepositoryStatic文件:存储静态的DateBaseContext对象,供其他程序集调用,实现线程内,使用同一个DateBaseContext对象,减少内存开销。

Repository的实现

TableModel

TableModel中我们建立了一个表——Kiba_User,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public partial class Kiba_User
{
    [Key]
    public int UserId { getset; }
    [Required]
    [StringLength(50)]
    public string UserName { getset; }
    [StringLength(200)]
    public string UserNickName { getset;
    [StringLength(100)]
    public string Password { getset; }
    public int? Age { getset; }
    public int? Sex { getset; }
    [StringLength(500)]
    public string Remark { getset; } 
}

代码很简单,就是把数据表和其字段转换成了类和属性,我们可以把这个类暂时理解为表的数据模型。

TableMapping

TableMapping中我们建立Kiba_User的数据模型表与数据库表的映射关系,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Kiba_UserMap : EntityTypeConfiguration<Kiba_User>
{
    public Kiba_UserMap()
    {
        this.Property(e => e.UserName)
          .IsUnicode(false);
        this.Property(e => e.UserNickName)
            .IsUnicode(false);
        this.Property(e => e.Password)
            .IsUnicode(false);
        this.Property(e => e.Remark)
            .IsUnicode(false); 
    }
}

从代码中我们可以发现,映射只对部分字符串类型的属性进行了映射,而其他属性,并没有做映射处理。

原因是这样的,没有显示映射处理的属性,会默认映射到同名的数据表字段上;所以这里节省了一些代码量。

DateBaseContext文件

表的数据模型和映射我们已经编写完了,并且,我们还编写了仓储用来对表进行操作;但,这样还不能让数据库和代码模型关联到一起。

我们还需要编写DateBaseContext文件,通过DateBaseContext文件编写,我们就可以把表模型和表映射与数据库关联了。

DateBaseContext文件的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public partial class DateBaseContext : DbContext
{
    public DateBaseContext()
        base("name=DateBaseContext")
    {
        this.Configuration.ValidateOnSaveEnabled = true;//保存时验证
        this.Configuration.AutoDetectChangesEnabled = true;//跟踪变化
        this.Configuration.LazyLoadingEnabled = true;//懒惰加载
        this.Configuration.ProxyCreationEnabled = true;//代理创建数据库
    }
    #region Table List
    public virtual DbSet<Kiba_User> Kiba_User { getset; }
    #endregion
    protected override void OnModelCreating(DbModelBuilder modelBuilde
    {
        modelBuilder.Configurations.Add(new Kiba_UserMap());
    }
}

代码很简单,下面我们一起来解读下DateBaseContext文件里的代码。

首先是DateBaseContext继承了DbContext类;DbContext可以理解为微软提供的,专门来管理数据库和代码之间的关系的类。

然后再构造函数DateBaseContext()里,可以看到,我们在构造函数中做了几项基础配置,代码中已经做了相应的注释。

其中this.Configuration.ProxyCreationEnabled属性,我们重点讲一下。

当ProxyCreationEnabled属性设置为True时,我们一旦运行系统,系统会自动的,数据模型同步到数据库,并且会创建一个__MigrationHistory表,来记录同步的内容。

PS:【虽然,在领域驱动设计的理念中,是先有表的数据模型,然后在建立表结构。但,这只是理念,我们运用的时候,先建立表在建立数据模型也是可以的。我这里只是为了简单的实现,所以将ProxyCreationEnabled设置为了True】

接下来,我们定义了一个public virtual DbSet<Kiba_User> Kiba_User { get; set; }属性。

Kiba_User 这个属性,我们可以把他理解为,数据库表在代码世界的代理,如果我们想对数据库表内容进行查询和修改,只要对这个代理进行修改,就会自动同步到数据库了。

然后我们重写了OnModelCreating方法,在OnModelCreating里,把我们刚刚建立的映射关系添加了进去,这样数据库的表,就被我们立体的加载到了代码世界。

TableRepository

TableRepository中主要是应用DateBaseContext来对表进行增删改查的处理,理论上TableRepository是修改数据库的唯一入口;

我们首先,先看下BaseRepository类;代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public class BaseRepository
{
    public DateBaseContext Database
    {
        get
        {
            var context = RepositoryStatic.DateBaseContext as DateBaseContext;
 
            if (context == null)
            {
                context = new DateBaseContext();
                RepositoryStatic.DateBaseContext = context;
            }
              
            return context;
        }
    }
    public int SaveChanges()
    {
        int i = 0;
        int saveCount = 0;
        bool saveFailed;
        do
        {
            saveFailed = false;
 
            try
            {
                saveCount++;
                i = Database.SaveChanges();
                Logger.Debug("SaveChanges Retrun:" + i);
 
            }
            catch (DbUpdateConcurrencyException ex)
            {
                if (saveCount > 3)
                {
                    throw new Exception("服务器繁忙,请稍后");
                }
                Logger.Error("DbUpdateConcurrencyException保存次数:" + saveCount, ex);
                saveFailed = true;
                try
                {
                    ex.Entries.Single().Reload();
                }
                catch (Exception exReload)
                {
                    Logger.Info("exReload保存失败");
                    throw exReload;
                }
            }
            catch (DbUpdateException ex)
            {
                if (ex.Message.Contains("与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。"))
                {
                    throw new Exception("服务器繁忙,请稍后");
                }
                else
                {
                    throw ex;
                }
            }
            catch (DbEntityValidationException dbEx)
            {
                Logger.Error(dbEx);
                throw dbEx;
            }
 
            catch (Exception ex)
            {
                Logger.Info("SaveChanges保存失败");
                throw ex;
            }
 
        while (saveFailed);
        return i;
    }
}

这里我们主要定义一个属性Database和一个方法SaveChanges。

Database就是DateBaseContext类的实例,相当于代码世界的数据库。

SaveChanges就是调用Database的SaveChanges方法来保存数据的修改,当然,我们对该方法进行了一些封装,让他更饱满一些。

然后我们在一起看下表的独立仓储Kiba_UserRepo,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Kiba_UserRepo : BaseRepository
{  
    public List<T> GetSelector<T>(Expression<Func<Kiba_User, T>> selector, Expression<Func<Kiba_User, bool>> where)
    {
        return Database.Kiba_User.Where(where).Select(selector).ToList();
    }
    public List<Kiba_User> GetWhere(Expression<Func<Kiba_User, bool>> whereint currentPage, int pageCount)
    {
        return Database.Kiba_User.Where(where).OrderByDescending(p => p.UserId).Skip((currentPage - 1) * pageCount).Take(pageCount).ToList();
    }
    public int GetWhereCount(Expression<Func<Kiba_User, bool>> where)
    {
        return Database.Kiba_User.Where(where).Count();
    }
    public Kiba_User Add(Kiba_User model)
    {
        var addModel = Database.Kiba_User.Add(model);
        return addModel;
    }
    public Kiba_User Delete(Kiba_User model)
    {
        var delModel = Database.Kiba_User.Remove(model);
        return delModel;
    }
}

表仓储里的代码很简单,就是普通的LINQ增删改查。

----------------------------------------------------------------------------------------------------

到此,框架的基本雏形就已经编写完成了,接下来我们做一下简单调用,测试一下。

在KibaDDD项目建立测试类——TestRun;代码如下:

1
2
3
4
5
6
7
8
9
public class TestRun
{
    public TestRun()
    {
        Kiba_UserRepo repo = new Kiba_UserRepo();
        repo.Add(new Kiba_User() { UserName = "kiba518" });
        repo.SaveChanges();
    }
}

运行结果:

数据库无中生有的,为我们创建了表Kiba_User,并且数据也顺利的插入进了数据库表。

这样,我们的领域驱动框架就已经完成了雏形搭建,下一篇文章将进一步搭建,实现领域驱动独有的聚合。

----------------------------------------------------------------------------------------------------

框架代码已经传到Github上了,欢迎大家下载。

Github地址:https://github.com/kiba518/KibaDDD

.net core +codefirst(.net core 基础入门,适合这方面的小白阅读) 【我们一起写框架】领域驱动设计的CodeFirst框架(一)—序篇的更多相关文章

  1. .net core +codefirst(.net core 基础入门,适合这方面的小白阅读,本文使用mysql或mssql)

    设置为model所在的那一层 前言 .net core mvc和 .net mvc开发很相似,比如 视图-模型-控制器结构.所以.net mvc开发员很容易入手.net core mvc .但是两个又 ...

  2. 【我们一起写框架】领域驱动设计的CodeFirst框架(一)—序篇

    前言 领域驱动设计,其实已经是一个很古老的概念了,但它的复杂度依旧让学习的人头疼不已. 互联网关于领域驱动的文章有很多,每一篇写的都很好,理解领域驱动设计的人都看的懂. 不过,这些文章对于那些初学者而 ...

  3. ASP.NET Core消息队列RabbitMQ基础入门实战演练

    一.课程介绍 人生苦短,我用.NET Core!消息队列RabbitMQ大家相比都不陌生,本次分享课程阿笨将给大家分享一下在一般项目中99%都会用到的消息队列MQ的一个实战业务运用场景.本次分享课程不 ...

  4. 【无私分享:ASP.NET CORE 项目实战(第三章)】EntityFramework下领域驱动设计的应用

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在我们 [无私分享:从入门到精通ASP.NET MVC] 系列中,我们其实也是有DDD思想的,但是没有完全的去实现,因为并不是 ...

  5. [.NET领域驱动设计实战系列]专题一:前期准备之EF CodeFirst

    一.前言 从去年已经接触领域驱动设计(Domain-Driven Design)了,当时就想自己搭建一个DDD框架,所以当时看了很多DDD方面的书,例如领域驱动模式与实战,领域驱动设计:软件核心复杂性 ...

  6. 如何使用ASP.NET Core、EF Core、ABP(ASP.NET Boilerplate)创建分层的Web应用程序(第一部分)

    本文是为了学习ABP的使用,是翻译ABP官方文档的一篇实战教程,我暂时是优先翻译自己感兴趣或者比较想学习的部分,后续有时间希望能将ABP系列翻译出来,除了自己能学习外,有可能的话希望帮助一些英文阅读能 ...

  7. .net core webapi +ddd(领域驱动)+nlog配置+swagger配置 学习笔记(2)

    DDD领域驱动模型设计 什么是DDD 软件开发不是一蹴而就的事情,我们不可能在不了解产品(或行业领域)的前提下进行软件开发,在开发前,通常需要进行大量的业务知识梳理,而后到达软件设计的层面,最后才是开 ...

  8. .NET正则表达式基础入门

    这是我第一次写的博客,个人觉得十分不容易.以前看别人写的博客文字十分流畅,到自己来写却发现十分困难,还是感谢那些为技术而奉献自己力量的人吧. 本教程编写之前,博主阅读了<正则指引>这本入门 ...

  9. 如何在Visual Studio 2017中使用C# 7+语法 构建NetCore应用框架之实战篇(二):BitAdminCore框架定位及架构 构建NetCore应用框架之实战篇系列 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架 NetCore入门篇:(十二)在IIS中部署Net Core程序

    如何在Visual Studio 2017中使用C# 7+语法   前言 之前不知看过哪位前辈的博文有点印象C# 7控制台开始支持执行异步方法,然后闲来无事,搞着,搞着没搞出来,然后就写了这篇博文,不 ...

随机推荐

  1. MyEclipse2015创建配置Web+Maven项目

    首先我的MyEclipse版本是2015 stable 2.0,在MyEclipse中创建Maven项目通常有两种常见的方式,它们分别是: New Maven Project  New Web Pro ...

  2. Android 应用程序的图标 (Icon) 应该设计成多大?

    应用程序图标 (Icon)应当是一个 Alpha 通道透明的32位 PNG 图片.由于安卓设备众多,一个应用程序图标需要设计几种不同大小,如:LDPI (Low Density Screen,120 ...

  3. OSChina.net 的 Tomcat 配置 server.xml 参考

    这是目前 oschina.net 正在使用的 tomcat 的 server.xml 的配置文件内容 <Server port="9005" shutdown="S ...

  4. hdu4445 CRAZY TANK 2012金华赛区现场赛D题

    简单推下物理公式  对角度枚举 物理公式不会推啊智商捉急啊.... 到现在没想通为什么用下面这个公式就可以包括角度大于90的情况啊... #include<iostream> #inclu ...

  5. Java效率工具之Lombok

    参考: http://www.54tianzhisheng.cn/2018/01/09/lombok/ https://zhuanlan.zhihu.com/p/32779910

  6. 需要掌握哪些python标准库和三方库?

    讨论参考:https://www.zhihu.com/question/20501628 库太多了,根据需要使用相应领域的三方库:至于对于企业常用的三方库,可以参考热门招聘网站的招聘说明

  7. 折叠伸缩工具栏 CollapsingToolbarLayout

    PS:这是一个超级超级垃圾的控件,强烈建议放弃使用! demo地址:https://github.com/baiqiantao/CollapsingDemo.git  一个类似的效果的库,有800个星 ...

  8. ArrayList的使用和List<T>的比较

    使用非泛型集合类的限制可以通过编写一小段程序来演示,该程序利用 .NET Framework 基类库中的 ArrayList 集合类.ArrayList 是一个使用起来非常方便的集合类,无需进行修改即 ...

  9. FatSecret Platform API

    在现阶段饮食类的APP发展的非常迅猛,尤其在校园中,学生只需要凭借一个手机就能买到自己想要的食物,真正做到了足不出户.可是如果我们想独立完成一个app就需要有相应的数据支持,这里给大家介绍一个国外的开 ...

  10. windows10 Sqlserver卸载 指定账户不存在

    在windows卸载程序时,有时会出现因提示“指定的账户不存在”而无法删除,如下: 这时时候要先选择要删除的项目,进行修复后再进行删除就可以正常删除了