• 使用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,启动服务器端

    运行客户端

    编译并运行EJClient.exe

    server url:https://localhost:6062

    user name:sa

    password:1

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

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

    再新建一个数据模块UserInfo

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

     

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

    编程使用数据表

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

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

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

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

     这样,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

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

    导航属性(一对一)

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

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

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

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

    这里要注意,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对话框,把导航属性改为这样:

    这时候,就必须选择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数据库

  • 相关阅读:
    05.迪米特原则 (LOD)
    04.接口隔离原则 (ISP)
    03.依赖倒置原则 (DIP)
    02.里氏替换原则 (LSP)
    01.单一职责原则 (SRP)
    Flutter点击事件的穿透,父元素点击事件覆盖了子元素点击的问题
    flutter dart语法判断 0/0==Nan 1/0==Infinity的问题
    vue项目引入三方字体
    vue echart图表打包后 图片不显示
    vue设置页面的高度100%
  • 原文地址:https://www.cnblogs.com/IWings/p/9304874.html
Copyright © 2020-2023  润新知