使用Way.EntityDB进行Entity Framework Core数据库建模

Way.EntityDB是一个基于EF Core的数据层框架,它取消了EF Core的Migration机制,因为Migration并不是通用的,比如说sql server生成的migration,如果换成sqlite,运行时会报错的,也就是数据库不能更换。

Way.EntityDB内置建模工具,通过图形化建表,生成Model对象代码,并且它会把表结构的修改过程,全部记录下来,涵盖在Model代码里面,所以,在新的代码运行时,数据库也会自动更新到最新结构。

 举个例子,当你把一个字段的名字从column1,更改为column2,EF Core生成的migration,就是把column1删除,并添加一个column2,这样,column1的现有数据就会丢失。而EntityDB则不一样,它只会把column1改名为column2,

因为它记录的是表结构修改的过程,而不是匹对Model类的前后变化。

 

Way.EntityDB源码位置:

https://github.com/simpleway2016/EntityDB

启动服务器端

Way.EntityDB是允许多人同时使用,所以,分为服务器和客户端。

下载源码,编译后,在Debug/netcoreapp2.0文件夹里面,创建一个批处理文件run6062.bat,内容如下:

dotnet Way.EJServer.dll 6062

6062是本机任意一个没有使用的端口号,表示以6062为端口,创建一个服务器工作空间

运行run6062.bat,启动服务器端

使用Way.EntityDB进行Entity Framework Core数据库建模

 

运行客户端

编译并运行EJClient.exe

server url:https://localhost:6062

user name:sa

password:1

使用Way.EntityDB进行Entity Framework Core数据库建模

登录进去,由于没有工程项目,所以界面空白,点击【project】菜单,创建一个项目

使用Way.EntityDB进行Entity Framework Core数据库建模

右键点击【Database】,新建一个数据库

使用Way.EntityDB进行Entity Framework Core数据库建模

再新建一个数据模块UserInfo

使用Way.EntityDB进行Entity Framework Core数据库建模

双击UserInfo,在数据模块里面,空白处点击右键,新建数据表

使用Way.EntityDB进行Entity Framework Core数据库建模

 

 

 使用Way.EntityDB进行Entity Framework Core数据库建模

使用Way.EntityDB进行Entity Framework Core数据库建模

这样,一张数据表就创建完成

编程使用数据表

新建一个.net core 控制台项目

使用Way.EntityDB进行Entity Framework Core数据库建模

给这个项目安装nuget包:Way.EntityDB

然后,回到EJClient,在TestDB处点击右键,点击【生成数据库模型代码】

使用Way.EntityDB进行Entity Framework Core数据库建模

保存到刚才创建的项目里面

使用Way.EntityDB进行Entity Framework Core数据库建模

使用Way.EntityDB进行Entity Framework Core数据库建模

 

 这样,Model类就准备好了,开始写代码

using System;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var db = new MyDB.DB.TestDB("data source='F:\\mytestdb.dat'", Way.EntityDB.DatabaseType.Sqlite);

            //插入数据
            var user = new MyDB.UserInfo() {
                UserName = "Jack",
                Password = "123"
            };

            //插入到数据库
            db.Update(user);


            //从数据库查询数据
            var userlist = (from m in db.UserInfo select m).ToArray();

            //修改数据
            var jack = db.UserInfo.FirstOrDefault(m => m.UserName == "Jack");
            jack.Password = "567";
            db.Update(jack);

            //删除数据
            db.Delete(jack);

//批量删除
db.Delete(db.UserInfo.Where( m => m.id > 0 ));
} } }

 

从代码可以看到,虽然也是EF Core,但由于禁用了ef的数据缓存机制,所以不能使用SaveChanges去同步数据库,可以使用DBContext.Insert  DBContext.Update  DBContext.Delete等方法同步数据库

DBContext.Update方法,会先判断对象的主键,如果主键是Null,那么会调用Insert方法,往数据库新增一条数据,如果主键不为Null,那么就是Update数据库里面的数据

禁用缓存机制,可以避免程序员在编程的时候混乱(有时候想把数据取出来,看看现在的数据状态,但谁知道取的是缓存里面的对象)

禁用缓存机制,对于大数据量的查询,也可以节约内存,提供效率,因为不再使用的对象,不会保存在内存里面

所以整体性能,应该和使用ADO.Net差不多

编写触发器 

 Way.EntityDB支持类似触发器的功能。添加一个ActionCapture类

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Way.EntityDB;
using System.Linq;

namespace ConsoleApp1
{
    class UserInfoTrigger : Way.EntityDB.ActionCapture<MyDB.UserInfo>
    {
        public override void AfterInsert(object database, DatabaseModifyEventArg e)
        {
            MyDB.UserInfo user = (MyDB.UserInfo)e.DataItem;
            Debug.WriteLine($"inserted {user.UserName}");
            base.AfterInsert(database, e);
        }

        public override void BeforeDelete(object database, DatabaseModifyEventArg e)
        {
            var db = database as MyDB.DB.TestDB;
            //由于删除的对象,可能只有主键有值,所以,需要获取删除对象的具体信息,需要到数据库把该对象取出来
            var pkid = ((MyDB.UserInfo)e.DataItem).id;
            var deletingUser = db.UserInfo.FirstOrDefault( m=>m.id == pkid);

            Debug.WriteLine($"准备删除 {deletingUser.UserName}");

            base.BeforeDelete(database, e);
        }

    }
}
class UserInfoTrigger : Way.EntityDB.ActionCapture<MyDB.UserInfo>  表示这个类捕获的是UserInfo表的事件
这时候,这个类还不能起作用,必须在程序启动时,把它实例化,注册到DBContext里面
        static Program()
        {
            Way.EntityDB.DBContext.RegisterActionCapture(new UserInfoTrigger());
        }

在ActionCapture类里面,只要override各个方法,就可以实现各种事件的捕获。

级联删除

 EJClient可以设置表之间的级联删除关系,并且,被级联删除的数据,同样可以被你编写的触发器捕捉到。

现在,我们新建一张数据表FamilyInfo

使用Way.EntityDB进行Entity Framework Core数据库建模

双击UserInfo,打开属性框,切换到【级联删除】项,添加一个级联删除关系

使用Way.EntityDB进行Entity Framework Core数据库建模

导航属性(一对一)

虽然UserInfo和FamilyInfo,在数据库中并没有建立关系,但是,从系统设计上来说,他们是有关系的,所以,在UserInfo里面,如果可以直接访问FamilyInfo,会比较方便,所以,

可以给他们添加导航属性,首先,我们假设他们是一对一的关系。

打开UserInfo属性窗口,切换到【导航属性】,并添加一个名称为Family的属性

使用Way.EntityDB进行Entity Framework Core数据库建模

然后,打开FamilyInfo属性窗口,添加一个User属性

使用Way.EntityDB进行Entity Framework Core数据库建模

这里要注意,UserInfo里面的Family属性,不需要选择ForeignKey,而FamilyInfo的User属性,必须选择ForeignKey

接着用EJClient生成Model代码

然后,代码,我们可以这样写了

using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace ConsoleApp1
{
    class Program
    {
        static Program()
        {
            Way.EntityDB.DBContext.RegisterActionCapture(new UserInfoTrigger());
        }

        static void Main(string[] args)
        {
            var db = new MyDB.DB.TestDB("data source='F:\\mytestdb.dat'", Way.EntityDB.DatabaseType.Sqlite);

            //插入数据
            var user = new MyDB.UserInfo() {
                UserName = "Jack",
                Password = "123"
            };

            //插入到数据库
            db.Update(user);

            //插入家庭信息
            var family = new MyDB.FamilyInfo() {
                UserId = user.id,
                MotherName = "李晴",
                FatherName = "刘星"
            };
            db.Update(family);

            //从数据库查询(m => m.Family 表示包含家庭信息)
            var jack = db.UserInfo.Include(m => m.Family).FirstOrDefault(m => m.UserName == "Jack");
            var montherName = jack.Family.MotherName;

            Debug.WriteLine($"mother is {montherName}");

            //删除数据
            db.Delete(jack);
        }
    }
}
var montherName = jack.Family.MotherName;直接可以取到母亲姓名,不需要到数据库再取一遍

 导航属性(一对多)

 如果UserInfo和FamilyInfo是一对多的关系,那么,打开userinfo对话框,把导航属性改为这样:

使用Way.EntityDB进行Entity Framework Core数据库建模

这时候,就必须选择ForeignKey了

用工具再次生成Model代码

这次的代码,就是这样写了:

using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace ConsoleApp1
{
    class Program
    {
        static Program()
        {
            Way.EntityDB.DBContext.RegisterActionCapture(new UserInfoTrigger());
        }

        static void Main(string[] args)
        {
            var db = new MyDB.DB.TestDB("data source='F:\\mytestdb.dat'", Way.EntityDB.DatabaseType.Sqlite);

            //插入数据
            var user = new MyDB.UserInfo() {
                UserName = "Jack",
                Password = "123"
            };

            //插入到数据库
            db.Update(user);

            //插入家庭信息
            var family1 = new MyDB.FamilyInfo() {
                UserId = user.id,
                MotherName = "李晴",
                FatherName = "刘星"
            };
            db.Update(family1);

            var family2 = new MyDB.FamilyInfo()
            {
                UserId = user.id,
                MotherName = "第二妈妈",
                FatherName = "第二爸爸"
            };
            db.Update(family2);

            //从数据库查询(m => m.Families 表示包含家庭信息)
            var jack = db.UserInfo.Include(m => m.Families).FirstOrDefault(m => m.UserName == "Jack");

            foreach (var family in jack.Families)
            {
                Debug.WriteLine($"mother is {family.MotherName}");
            }

            //删除数据
            db.Delete(jack);
        }
    }
}

 变更数据库类型

如果在开发过程中,你要变更数据库类型,只需要更改连接字符串和类型即可

 var db = new MyDB.DB.TestDB("server=192.168.136.137;uid=sa;pwd=Sql12345678;Database=TestDB", Way.EntityDB.DatabaseType.SqlServer);

这样,就转而使用SqlServer数据库