软件设计模式应用到 EF (ORM)

前言

本来不想写前言的,但突然想说一些话。之前去面试,好多公司都再问 Sql 语句或者数据库存储过程等的问题,但却没有人问如何使用EF,代码如何设计,设计如可应用到数据库等,似乎好多公司都不注重设计
好了,简单说明一下ORM,ORM并不是让我们更快的进行增删改查,而是让我们的设计能够映射到数据库上,下面介绍一些设计如何持久化到数据库(不定期更新)

值对象

值对象没有对应的数据库表

    class MyContext : DbContext
    {
        public MyContext(DbContextOptions<MyContext> options) : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            modelBuilder.Entity<Person>().OwnsOne(e => e.ValueObject);
        }

        public DbSet<Person> Persons { get; set; }
	}

    public class Person
    {
        public int Id { get; set; }

        public ValueObject ValueObject { get; set; }
	}

    public class ValueObject
    { 
        public string State { get; set; }
    }

数据库字段
在这里插入图片描述

继承模式

    class MyContext : DbContext
    {
        public MyContext(DbContextOptions<MyContext> options) : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder) 
        {
            modelBuilder.Entity<Person>().HasDiscriminator(e => e.Type).HasValue<SmallPerson>("SmallPerson").HasValue<BigPerson>("BigPerson");
        }

        public DbSet<Person> Persons { get; set; }
	}

    public abstract class Person
    {
        public int Id { get; set; }

        public string Type { get; set; }
	}

    public class SmallPerson : Person
    { 
        public string SmallPersonField { get; set; }
	}

    public class BigPerson : Person 
    {
        public string BigPersonField { get; set; }
    }

数据库字段
在这里插入图片描述

注:多继承的数据保存在一张表上,但在 EF6 和 EFCore 5.0(2020.11发布) 上可以支持每个实体对应一张表

另一种多表保存的设计

class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder) 
    {
    }

    public DbSet<SmallPerson> SmallPersons { get; set; }

    public DbSet<BigPerson> BigPersons { get; set; }
}

数据库字段
在这里插入图片描述

这种设计使用每个实体都有各自的数据库表,但这种设计只是在代码上实现的继承,但数据库中并没有实现继承,举个例子:查找最近添加的10个Person,怎么查找?

状态模式

原本状态类是想使用值对象,但EFCore值对象模式不支持集成,所以只能使用实体

    class MyContext : DbContext
    {
        public MyContext(DbContextOptions<MyContext> options) : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            modelBuilder.Entity<Person>();
            modelBuilder.Entity<StateBase>().HasDiscriminator(e => e.State).HasValue<State1>("State1").HasValue<State2>("State2");
        }

        public DbSet<Person> Persons { get; set; }
	}

    // 人
    public class Person
    {
        public int Id { get; set; }

        // 人的状态
        public StateBase State { get; set; }
	}

    // 状态基类
    public abstract class StateBase 
    { 
        public int Id { get; set; }

        public string State { get; set; }
	}

    // 状态1
    public class State1: StateBase
    {
        public string FieldState1 { get; set; }
	}

    // 状态2
    public class State2: StateBase
    {
        public string FieldState2 { get; set; }
    }

数据库字段
在这里插入图片描述

规格

如,有一个需求,绳索的载重量必须是大于电梯载重量的2倍
实际上这是一个规格的设计,但规格并不保存再数据库中,所以EF实现起来也是比较简单

    class MyContext : DbContext
    {
        public MyContext(DbContextOptions<MyContext> options) : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder) 
        {
        }

        public DbSet<Lift> Lifts { get; set; }
	}

    /// <summary>
    /// 电梯
    /// </summary>
    public class Lift
    {
        public int Id { get; set; }

        // 载重量
        public int Carry { get; set; }

        public Line Line { get; set; }
	}

    /// <summary>
    /// 挂载电梯的绳锁
    /// </summary>
    public class Line
    {
        public int Id { get; set; }

        // 载重量
        public int Carry { get; set; }
	}

    /// <summary>
    /// 电梯载重量约束(规格)
    /// </summary>
    public class LiftCarryCheck
    {
        public bool Check(Lift lift) {
            return lift.Carry * 2 < lift.Line.Carry;
        }
    }

组合模式

哎,没什么好说的,看代码

    class MyContext : DbContext
    {
        public MyContext(DbContextOptions<MyContext> options) : base(options) { }

        protected override void OnModelCreating(ModelBuilder modelBuilder) 
        {
            modelBuilder.Entity<Menu>().HasDiscriminator(e => e.MenuType).HasValue<LiftMenu>("LiftMenu").HasValue<ComposeMenu>("ComposeMenu");
        }

        public DbSet<Menu> Menus { get; set; }
	}

    /// <summary>
    /// 菜单
    /// </summary>
    public abstract class Menu
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public string MenuType { get; set; }
	}

    /// <summary>
    /// 叶子菜单
    /// </summary>
    public class LiftMenu : Menu
    {
	}

    /// <summary>
    /// 组合菜单
    /// </summary>
    public class ComposeMenu: Menu
    {
        public IQueryable<Menu> Childs { get; set; }
    }

数据库字段
在这里插入图片描述

值得一提的是,上面的MyContext中,我一般只DBSet一个实体,因为大多数情况我们只公布根实体,具体原因查看领域驱动设计 领域驱动设计链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值