在很多个世纪前,老周曾写过实体之间普通关系(一对一,一对多,多对多)与 Owned 关系的区别。不过,那次写得比较粗浅,逼格不够高,于是,老周厚着脸皮地决定重新写一下。

首先,为什么这次老周用原单词 Owned 呢,官方文档目前的翻译(怀疑是机器干的)为“从属”,这种说法与普通关系数据库中一对多、多对多等关系描述不太 好区分。其实老周觉得应该把 Owned 翻译为“独占”关系——你完全属于我的。普通关系中的厕所是公共厕所,我可以用,邻居A、B、C也可以用;而 Owned 关系中的厕所是私人的,我用我家的厕所,A用A家自己的厕所,B不能用A家的厕所。

这种玩意儿比某少年马戏团的粉丝还抽象,要理解最好的方法是比较。本文老周就对这两类关系做一轮大比拼。

One and One

首先我们来看“一”和“一”的方式。为了保持数据结构的一致,咱们用这三个实体来实验。

public class HardwareInfo
{
public int HwID { get; set; } // 主键
public long MemorySize { get; set; } // 内存大小
public int HarddiskNum { get; set; } // 硬盘数量
public long HDDSize { get; set; } // 硬盘大小
public bool InteGrp { get; set; } // 是否有集显
} public class Desktop
{
public int ID { get; set; } // 主键
public HardwareInfo HWInfo { get; set; } // 硬件信息
} public class Laptop
{
public int ID { get; set; } // 主键
public HardwareInfo HWInfo { get; set; } // 硬件信息
}

HardwareInfo 表示硬件参数,不管是台式机(Desktop)还是笔记本(Laptop)都可以共用这样的数据结构。

先定义用在普通关系的上下文类——MyContextR,R结尾表示 Relational。

public class MyContextR : DbContext
{
public DbSet<Desktop> PCs { get; set; }
public DbSet<Laptop> Laps { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"server=<你的服务器>;database=rdb")
.LogTo(m => Debug.WriteLine(m));
} protected override void OnModelCreating(ModelBuilder mb)
{
// 配置主键
mb.Entity<HardwareInfo>().HasKey(m => m.HwID); mb.Entity<Laptop>(ent =>
{
ent.HasKey(k => k.ID);
ent.HasOne(x => x.HWInfo);
});
mb.Entity<Desktop>(eb =>
{
eb.HasKey(a => a.ID);
eb.HasOne(y => y.HWInfo);
});
}
}

由于老周在定义实体类时“粗心大意”,主键属性的命名无法让 EF Core 自动识别,所以要在 OnModelCreating 方法中显式配置一下。注意,HasOne 让它们建立一对一的关系,即PC有一个HardwareInfo 实例,笔记本也有。

第二个上下文类是面向“独占”关系的 MyContextO,O 结尾表示 Owned。

public class MyContextO : DbContext
{
public DbSet<Laptop> Laps { get; set; }
public DbSet<Desktop> PCs { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"server=<你的服务器>;database=odb")
.LogTo(g => Debug.WriteLine(g));
} protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Laptop>().HasKey(m => m.ID);
mb.Entity<Desktop>().HasKey(n => n.ID);
mb.Entity<Laptop>().OwnsOne(x => x.HWInfo);
mb.Entity<Desktop>().OwnsOne(w => w.HWInfo);
}
}

OwnsOne 表示一占一,PC占用一个HardwareInfo实例,笔记本也占用一个,两者不相干。这种情形 HardwareInfo 是不需要主键的,为什么?往下看你就懂了。

咱们依次实例化这两个上下文对象,然后让它自己创建数据库。

static void Main(string[] args)
{
using MyContextR c1 = new();
c1.Database.EnsureCreated(); using MyContextO c2 = new();
c2.Database.EnsureCreated();
}

实验结果发现,普通一对一关系中,创建了三个表:

CREATE TABLE [HardwareInfo] (
[HwID] int NOT NULL IDENTITY,
[MemorySize] bigint NOT NULL,
[HarddiskNum] int NOT NULL,
[HDDSize] bigint NOT NULL,
[InteGrp] bit NOT NULL,
CONSTRAINT [PK_HardwareInfo] PRIMARY KEY ([HwID]); CREATE TABLE [Laps] (
[ID] int NOT NULL IDENTITY,
[HWInfoHwID] int NULL,
CONSTRAINT [PK_Laps] PRIMARY KEY ([ID]),
CONSTRAINT [FK_Laps_HardwareInfo_HWInfoHwID] FOREIGN KEY ([HWInfoHwID]) REFERENCES [HardwareInfo] ([HwID])
); CREATE TABLE [PCs] (
[ID] int NOT NULL IDENTITY,
[HWInfoHwID] int NULL,
CONSTRAINT [PK_PCs] PRIMARY KEY ([ID]),
CONSTRAINT [FK_PCs_HardwareInfo_HWInfoHwID] FOREIGN KEY ([HWInfoHwID]) REFERENCES [HardwareInfo] ([HwID])
);

EF Core 这货还挺聪明的,把外键分别放在 Desktop 和 Laptop 中,这样可避免在 HardwareInfo 中出现两个外键,不好约束。毕竟这是一对一关系,外键放在哪一端都可以。

然后看看“独占”关系中的一对一,它创建了两个表:

CREATE TABLE [Laps] (
[ID] int NOT NULL IDENTITY,
[HWInfo_HwID] int NULL,
[HWInfo_MemorySize] bigint NULL,
[HWInfo_HarddiskNum] int NULL,
[HWInfo_HDDSize] bigint NULL,
[HWInfo_InteGrp] bit NULL,
CONSTRAINT [PK_Laps] PRIMARY KEY ([ID])
); CREATE TABLE [PCs] (
[ID] int NOT NULL IDENTITY,
[HWInfo_HwID] int NULL,
[HWInfo_MemorySize] bigint NULL,
[HWInfo_HarddiskNum] int NULL,
[HWInfo_HDDSize] bigint NULL,
[HWInfo_InteGrp] bit NULL,
CONSTRAINT [PK_PCs] PRIMARY KEY ([ID])
);

你没看错,只有两个表,HardwareInfo 直接被拆开了,Desktop和Laptop各拥有一份。现在你明白了吧,为什么 HardwareInfo 在这种关系下不需要主键,因为它们不独成表。

那么,如果让 HardwareInfo 独立建表呢,又会怎样?咱们把 MyContextO 类的代码改一下,为 HardwareInfo 类单独建表。

public class MyContextO : DbContext
{
public DbSet<Laptop> Laps { get; set; }
public DbSet<Desktop> PCs { get; set; } …… protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Desktop>(et =>
{
et.HasKey(a => a.ID);
et.OwnsOne(b => b.HWInfo, ob =>
{
ob.ToTable("Desktop_HW");
ob.WithOwner();
});
});
mb.Entity<Laptop>(et =>
{
et.HasKey(a => a.ID);
et.OwnsOne(m => m.HWInfo, ob =>
{
ob.ToTable("Laptop_HW");
ob.WithOwner();
});
});
}
}

这个地方,WithOwner 方法可以不调用,因为 HardwareInfo 类没有定义指向 Laptop 或 Desktop 的反向导航属性。

这一次,会创建四个表:

CREATE TABLE [Desktop_HW] (
[DesktopID] int NOT NULL,
[HwID] int NOT NULL,
[MemorySize] bigint NOT NULL,
[HarddiskNum] int NOT NULL,
[HDDSize] bigint NOT NULL,
[InteGrp] bit NOT NULL,
CONSTRAINT [PK_Desktop_HW] PRIMARY KEY ([DesktopID]),
CONSTRAINT [FK_Desktop_HW_PCs_DesktopID] FOREIGN KEY ([DesktopID]) REFERENCES [PCs] ([ID]) ON DELETE CASCADE
); CREATE TABLE [Laptop_HW] (
[LaptopID] int NOT NULL,
[HwID] int NOT NULL,
[MemorySize] bigint NOT NULL,
[HarddiskNum] int NOT NULL,
[HDDSize] bigint NOT NULL,
[InteGrp] bit NOT NULL,
CONSTRAINT [PK_Laptop_HW] PRIMARY KEY ([LaptopID]),
CONSTRAINT [FK_Laptop_HW_Laps_LaptopID] FOREIGN KEY ([LaptopID]) REFERENCES [Laps] ([ID]) ON DELETE CASCADE
); CREATE TABLE [PCs] (
[ID] int NOT NULL IDENTITY,
CONSTRAINT [PK_PCs] PRIMARY KEY ([ID])
); CREATE TABLE [Laps] (
[ID] int NOT NULL IDENTITY,
CONSTRAINT [PK_Laps] PRIMARY KEY ([ID])
);

EF Core 很有才,咱们没有为 HardwareInfo 定义主键,于是它自己生成了,在 Laptop_HW 表中生成 LaptopID 列作为主键,同时也作为外键,引用 Laptop.ID;在 Desktop_HW 表中生成了 DesktopID 列作为主键,同时作为外键,引用 Desktop.ID。

还要补充解释一下模型配置代码。

 mb.Entity<Laptop>(et =>
{
et.HasKey(a => a.ID);
et.OwnsOne(m => m.HWInfo, ob =>
{
ob.ToTable("Laptop_HW");
//ob.WithOwner();
});
});

ToTable 的调用在此处是必须的,否则按默认约定,它会使用表名 Laps,即和 Laptop 保持一致,这会导致出错。而且,Laptop 和 Desktop 不能共享一个 HardwareInfo 实体。这样配置也会报错:

protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Desktop>(et =>
{
et.HasKey(a => a.ID);
et.OwnsOne(b => b.HWInfo, ob =>
{
ob.ToTable("HW_info");
});
});
mb.Entity<Laptop>(et =>
{
et.HasKey(a => a.ID);
et.OwnsOne(m => m.HWInfo, ob =>
{
ob.ToTable("HW_info");
});
});
}

这就等于 Desktop 和 Laptop 同时占有相同的 HardwareInfo 实例,运行时也会报错。

One and Many

这里咱们已经没有必要再与普通的一对多关系对比了,上面的对比已经明确 Owned 关系是独占性的,不共享实例。下面咱们看看实体独占多个实例的情况。这种情况下,被占有的对象不会与主对象共用一个表了——拆分的列无法表示多个实例。

举个例子。

public class AddressInfo
{
/// <summary>
/// 这里有主键
/// </summary>
public int AddrID { get; set; }
/// <summary>
/// 省
/// </summary>
public string Province { get; set; } = "";
/// <summary>
/// 市
/// </summary>
public string City { get; set; } = "";
/// <summary>
/// 镇
/// </summary>
public string Town { get; set; } = "";
/// <summary>
/// 路
/// </summary>
public string Road { get; set; } = "";
/// <summary>
/// 街道
/// </summary>
public string Street { get; set; } = "";
/// <summary>
/// 邮编
/// </summary>
public string? ZipCode { get; set; }
} public class Student
{
public int StudentID { get; set; }
public IList<AddressInfo>? Addresses { get; set; }
}

如果这里的地址表示收货地址,于是每个学生都可以拥有多个地址。

然后,上下文类是这样的。

public class MyContext : DbContext
{
public DbSet<Student> Students { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder ob)
{
SqlConnectionStringBuilder strbd = new();
strbd.DataSource = <你的服务器>;
strbd.InitialCatalog = "TestDB";
ob.UseSqlServer(strbd.ConnectionString)
.LogTo(x => Console.WriteLine(x));
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>(ste =>
{
ste.HasKey(x => x.StudentID).HasName("PK_Stu_id");
// 它占有多个 Addr
ste.OwnsMany(k => k.Addresses, ob =>
{
// 此处可以配置主键
ob.HasKey(x => x.AddrID);
ob.WithOwner()
.HasForeignKey("stu_id").HasConstraintName("FK_StuID");
});
});
}
}

数据库会创建两张表:

CREATE TABLE [Students] (
[StudentID] int NOT NULL IDENTITY,
CONSTRAINT [PK_Stu_id] PRIMARY KEY ([StudentID])
); CREATE TABLE [AddressInfo] (
[AddrID] int NOT NULL IDENTITY,
[Province] nvarchar(max) NOT NULL,
[City] nvarchar(max) NOT NULL,
[Town] nvarchar(max) NOT NULL,
[Road] nvarchar(max) NOT NULL,
[Street] nvarchar(max) NOT NULL,
[ZipCode] nvarchar(max) NULL,
[stu_id] int NOT NULL,
CONSTRAINT [PK_AddressInfo] PRIMARY KEY ([AddrID]),
CONSTRAINT [FK_StuID] FOREIGN KEY ([stu_id]) REFERENCES [Students] ([StudentID]) ON DELETE CASCADE
);

AddressInfo 表会创建一个外键来引用 Students 表的主键列。

接着,咱们加一个 Teacher 实体,和学生一样,老师也有多个收货地址。

public class Teacher
{
public int Tid { get; set; }
public IList<AddressInfo>? Addresses { get; set; }
}

上下文类也要做相应修改。

public class MyContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; } …… protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>(ste =>
{
ste.HasKey(x => x.StudentID).HasName("PK_Stu_id");
// 它占有多个 Addr
ste.OwnsMany(k => k.Addresses, ob =>
{
// 此处可以配置主键
ob.HasKey(x => x.AddrID);
// 必须要表名
ob.ToTable("Stu_Addr");
ob.WithOwner()
.HasForeignKey("stu_id").HasConstraintName("FK_StuID");
});
}); modelBuilder.Entity<Teacher>(tet =>
{
tet.HasKey(t => t.Tid).HasName("PK_TeacherID");
// 占用多个地址
tet.OwnsMany(t => t.Addresses, ob =>
{
ob.HasKey(o => o.AddrID); // 主键
ob.ToTable("Teacher_Addr"); // 表名
ob.WithOwner().HasForeignKey("teach_id").HasConstraintName("FK_TeachID");
});
});
}
}

这种情况下必须配置 AddressInfo 的表名。

这样数据库会创建四张表:

CREATE TABLE [Students] (
[StudentID] int NOT NULL IDENTITY,
CONSTRAINT [PK_Stu_id] PRIMARY KEY ([StudentID])
); CREATE TABLE [Teachers] (
[Tid] int NOT NULL IDENTITY,
CONSTRAINT [PK_TeacherID] PRIMARY KEY ([Tid])
); CREATE TABLE [Stu_Addr] (
[AddrID] int NOT NULL IDENTITY,
[Province] nvarchar(max) NOT NULL,
[City] nvarchar(max) NOT NULL,
[Town] nvarchar(max) NOT NULL,
[Road] nvarchar(max) NOT NULL,
[Street] nvarchar(max) NOT NULL,
[ZipCode] nvarchar(max) NULL,
[stu_id] int NOT NULL,
CONSTRAINT [PK_Stu_Addr] PRIMARY KEY ([AddrID]),
CONSTRAINT [FK_StuID] FOREIGN KEY ([stu_id]) REFERENCES [Students] ([StudentID]) ON DELETE CASCADE
); CREATE TABLE [Teacher_Addr] (
[AddrID] int NOT NULL IDENTITY,
[Province] nvarchar(max) NOT NULL,
[City] nvarchar(max) NOT NULL,
[Town] nvarchar(max) NOT NULL,
[Road] nvarchar(max) NOT NULL,
[Street] nvarchar(max) NOT NULL,
[ZipCode] nvarchar(max) NULL,
[teach_id] int NOT NULL,
CONSTRAINT [PK_Teacher_Addr] PRIMARY KEY ([AddrID]),
CONSTRAINT [FK_TeachID] FOREIGN KEY ([teach_id]) REFERENCES [Teachers] ([Tid]) ON DELETE CASCADE
);

最后,咱们验证一下,Owned 关系是否真的不能共享实例。

using(MyContext c = new())
{
// 四个地址
AddressInfo addr1 = new()
{
Province = "冬瓜省",
City = "嘎子市",
Town = "小连子镇",
Road = "牛逼路",
Street = "春风街3999号",
ZipCode = "62347"
};
AddressInfo addr2 = new()
{
Province = "提头省",
City = "抬扛台",
Town = "烟斗镇",
Road = "王八路",
Street = "送人头街666号",
ZipCode = "833433"
}; // 教师实例
Teacher tt = new();
// 学生实例
Student ss = new();
// 让他们使用相同的地址实例
tt.Addresses = new List<AddressInfo>( [addr1, addr2] );
ss.Addresses = new List<AddressInfo>( [addr1, addr2] ); // 添加实体
c.Students.Add(ss);
c.Teachers.Add(tt); // 保存到数据库
c.SaveChanges();
}

运行后,未抛出异常,但有警告。而且数据库中也有数据。

下面咱们改一下某个地址的 City 属性。

using(MyContext c2 = new())
{
var r1 = c2.Students.ToArray();
var r2 = c2.Teachers.ToArray();
AddressInfo? addr = r1.First()?.Addresses?.FirstOrDefault();
if(addr != null)
{
addr.City = "烤鸭市";
}
c2.SaveChanges();
}

运行一下。

然后咱们查询一下两个地址表的数据。

select * from Stu_Addr;
select * from Teacher_Addr;

只有 ID = 1 的学生的第一个地址的 City 属性被更新,而教师地址未更新。可见,两个实体是不共响地址实例的。这很好理解嘛,毕竟是两个表的。

那么,如果把 Student - AddressInfo,Teacher - AddressInfo 的关系改为普通的一对多关系,又会怎样?

public class MyContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder ob)
{
……
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>(ste =>
{
ste.HasKey(x => x.StudentID).HasName("PK_Stu_id"); ste.HasMany(x => x.Addresses)
.WithOne()
.HasForeignKey("stu_id")
.HasConstraintName("FK_StuID");
}); modelBuilder.Entity<Teacher>(tet =>
{
tet.HasKey(t => t.Tid).HasName("PK_TeacherID"); tet.HasMany(f => f.Addresses)
.WithOne()
.HasForeignKey("teacher_id")
.HasConstraintName("FK_TeacherID");
}); // 注意:这时候 AddressInfo 实体需要主键
modelBuilder.Entity<AddressInfo>().HasKey(x => x.AddrID);
}
}

改为普通一对多关系时要注意,Student、Teacher、AddressInfo 三个实体都需要主键的, Owned 实体、复合类型(老周以前介绍过)这些不需要主键。

删除刚刚的数据库,重新建立新的数据库,然后写入数据。

using(MyContext c = new())
{
c.Database.EnsureDeleted();
c.Database.EnsureCreated();
// 两个地址
AddressInfo addr1 = new()
{
Province = "冬瓜省",
City = "嘎子市",
Town = "小连子镇",
Road = "牛逼路",
Street = "春风街3999号",
ZipCode = "62347"
};
AddressInfo addr2 = new()
{
Province = "提头省",
City = "抬扛台",
Town = "烟斗镇",
Road = "王八路",
Street = "送人头街666号",
ZipCode = "833433"
}; // 教师实例
Teacher tt = new();
// 学生实例
Student ss = new();
// 让他们使用相同的地址实例
tt.Addresses = new List<AddressInfo>( [addr1, addr2] );
ss.Addresses = new List<AddressInfo>( [addr1, addr2] ); // 添加实体
c.Students.Add(ss);
c.Teachers.Add(tt); // 保存到数据库
c.SaveChanges();
}

这时候,地址表只有一个,插入的数据如下:

教师和学生共享一个地址表,分别通过 stu_id 和 teacher_id 外键引用主表记录。

然后更改第一个地址的 City 属性。

 using(MyContext c2 = new())
{
var r1 = c2.Students.Include(s => s.Addresses).ToArray();
var r2 = c2.Teachers.Include(t => t.Addresses).ToArray();
AddressInfo? addr = r1.First()?.Addresses?.FirstOrDefault();
if(addr != null)
{
addr.City = "烤鸭市";
}
c2.SaveChanges();
}

地址表的数据变为:

由于教师和学生共用一个地址表,所以他们的地址信息会相同。

 using(MyContext c3 = new())
{
// 加载全部数据
var students = c3.Students.Include(x => x.Addresses);
var teachers = c3.Teachers.Include(x => x.Addresses); Console.WriteLine("---------- 学生 ---------");
foreach(var s in students)
{
Console.WriteLine($"学生:{s.StudentID}");
if(s.Addresses != null)
{
foreach(var a in s.Addresses)
{
Console.WriteLine($"\t{a.AddrID}, {a.Province}, {a.City}, {a.Town}");
}
}
} Console.WriteLine("\n---------- 教师 ---------");
foreach (var t in teachers)
{
Console.WriteLine($"老师:{t.Tid}");
if (t.Addresses != null)
{
foreach (var a in t.Addresses)
{
Console.WriteLine($"\t{a.AddrID}, {a.Province}, {a.City}, {a.Town}");
}
}
} }

【总结】

1、Owned 关系中,主实体完全掌控从实体,并且不与其他实体共享数据;

2、被“独占”的实体不用使用 ModelBuilder.Entity<T> 方法配置,因此在 DbContext 派生时,也不能声明为 DbSet<T> 属性。而普通关系中的实体是允许的;

3、Owned 关系有一 Own 一、一 Own 多,不存在 多 Own 多。多 Own 多 就违背“独占”原则了。普通关系中可以有多对多;

【EF Core】再谈普通实体关系与 Owned 关系的区别的更多相关文章

  1. EF Core怎么只Update实体的部分列数据

    下面是EF Core中的一个Person实体: public partial class Person { public int Id { get; set; } public string Code ...

  2. EF Core 2.0 已经支持自动生成父子关系表的实体

    现在我们在SQL Server数据库中有Person表如下: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ) NULL, ) NULL, [Cr ...

  3. EF Core中如何通过实体集合属性删除从表的数据

    假设在数据库中有两个表:Person表和Book表,Person和Book是一对多关系 Person表数据: Book表数据: 可以看到数据库Book表中所有的数据都属于Person表中"F ...

  4. EF Core中,通过实体类向SQL Server数据库表中插入数据后,实体对象是如何得到数据库表中的默认值的

    我们使用EF Core的实体类向SQL Server数据库表中插入数据后,如果数据库表中有自增列或默认值列,那么EF Core的实体对象也会返回插入到数据库表中的默认值. 下面我们通过例子来展示,EF ...

  5. DDD:再谈:实体能否处于非法状态?

    背景 实体能否处于非法状态吗?如果实体只承担其作为实体的职责,我不认为实体可以处于非法状态,如果您将实体在不同的分层之间传递,如:UI->Application->Domain-Data, ...

  6. WithOne 实体关系引起 EF Core 自动删除数据

    最近遇到了一个 EF Core 的恐怖问题,在添加数据时竟然会自动删除数据库中已存在的数据,经过追查发现是一个多余的实体关系配置引起的. modelBuilder.Entity<Question ...

  7. EF Core 快速上手——EF Core的三种主要关系类型

    系列文章 EF Core 快速上手--EF Core 入门 本节导航 三种数据库关系类型建模 Migration方式创建和习修改数据库 定义和创建应用DbContext 将复杂查询拆分为子查询   本 ...

  8. EF Core 2.0中如何手动映射数据库的视图为实体

    由于Scaffold-DbContext指令目前还不支持自动映射数据库中的视图为实体,所以当我们想使用EF Core来读取数据库视图数据的时候,我们需要手动去做映射,本文介绍如何在EF Core中手动 ...

  9. EF Core中如何正确地设置两张表之间的关联关系

    数据库 假设现在我们在SQL Server数据库中有下面两张表: Person表,代表的是一个人: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ...

  10. 深入理解 EF Core:EF Core 写入数据时发生了什么?

    阅读本文大概需要 14 分钟. 原文:https://bit.ly/2C67m1C 作者:Jon P Smith 翻译:王亮 声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的.其中可能 ...

随机推荐

  1. ASP.NET 5 with Dapr 初体验

    分布式应用运行时Dapr目前已经发布了1.1.0版本,阿里云也在积极地为Dapr贡献代码和落地实践.作为一名开发者,自然也想玩一玩,看看Dapr带来的新"视"界到底是怎么样的. 1 ...

  2. (一)Qt与Python—PySide的简介及安装

    目录 1.Pyside的简介 2.pyside的安装 3.pyside的Hello world程序 4.参考文献及网站连接 1.Pyside的简介 ​ PySide(在本文中指代PySide2和PyS ...

  3. Xamarin.Andorid 监听 EditText 回车事件

    EditText ET_Billcode.EditorAction += ET_Billcode_EditorAction; //执行方法 private void ET_Billcode_Edito ...

  4. java--servelt编程

    Servlet的映射路径 <servlet-mapping> <!-- servlet的内部名称,一定要和上面的内部名称保持一致!! --> <servlet-name& ...

  5. openWrt安装三方插件

    前言 openWrt是一款开源的路由器系统,其最大的优点就是 支持第三方扩展插件. 新增的插件基本都会在左侧的服务菜单中展现,通过此入口就可以使用插件功能. 大部分openWrt固件都帮你装好了ope ...

  6. C++求最长的一条食物链的长度。DFS深度优先算法

    题目描述 如图所示为某生态系统的食物网示意图,据图回答第一小题. 1. 数一数,在这个食物网中最长的食物链包含的物种数是 ( ) ...... 现在给你 n 个物种和 m 条能量流动关系,求其中的食物 ...

  7. sublime3 教程 比较好的

    因为不让转载 所以列出 地址http://www.cnblogs.com/figure9/p/sublime-text-complete-guide.html 关键技术要点: Ctrl + ←/→进行 ...

  8. 企业API网关适用业务场景

    什么是企业级API网关 企业级API网关是一种用于管理.保护和监控企业内部和外部API(Application Programming Interface)的解决方案.它提供了一套统一的接入点,帮助企 ...

  9. MCU/CPU/*PU的 WatchDog/看门狗 使用注意事项

    MCU/CPU/*PU的 WatchDog/看门狗 使用注意事项 类比于 Heartbeat/心跳 检测多用在软件及服务领域, WatchDog/看门狗 多用在硬件与系统领域(硬件看门狗), 也有用在 ...

  10. Win10纯净版电脑录屏功能不可用的问题

    有很多深度官网的小伙伴,都知道在Windows 10系统有录屏功能,而有win10纯净版的用户,打开自带录屏功能却突然失败了的问题,这该怎么解决呢?下面深度技术小编就带大家看看详细的处理方法,可以参考 ...