典型实现
典型的实现如下所示,并在其实体上使用外键属性Street
(引用City.Id
):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class City
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Street> Streets { get; set; } = new HashSet<Street>();
}
public class Street
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid CityId { get; set; } // <-- foreign key, referencing City.Id
}
public class Context : DbContext
{
public DbSet<City> Cities { get; set; }
public DbSet<Street> Streets { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connectionString = "server=127.0.0.1;port=3306;user=root;password=;database=So68982686";
var serverVersion = ServerVersion.AutoDetect(connectionString);
optionsBuilder
.UseMySql(connectionString, serverVersion)
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
}
internal static class Program
{
private static void Main()
{
using (var context = new Context())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var city = new City { Name = "Berlin" };
city.Streets.Add(new Street { Name = "Potsdamer Platz" });
context.Cities.Add(city);
context.SaveChanges();
}
using (var context = new Context())
{
var city = context.Cities
.Include(c => c.Streets)
.First();
Trace.Assert(city.Name == "Berlin");
Trace.Assert(city.Streets.Count == 1);
Trace.Assert(city.Streets.First().Name == "Potsdamer Platz");
}
}
}
}
将生成以下 SQL:
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE DATABASE `So68982686`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
ALTER DATABASE CHARACTER SET utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (22ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE `Cities` (
`Id` char(36) COLLATE ascii_general_ci NOT NULL,
`Name` longtext CHARACTER SET utf8mb4 NULL,
CONSTRAINT `PK_Cities` PRIMARY KEY (`Id`)
) CHARACTER SET=utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (31ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE `Streets` (
`Id` char(36) COLLATE ascii_general_ci NOT NULL,
`Name` longtext CHARACTER SET utf8mb4 NULL,
`CityId` char(36) COLLATE ascii_general_ci NOT NULL,
CONSTRAINT `PK_Streets` PRIMARY KEY (`Id`),
CONSTRAINT `FK_Streets_Cities_CityId` FOREIGN KEY (`CityId`) REFERENCES `Cities` (`Id`) ON DELETE CASCADE
) CHARACTER SET=utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (25ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE INDEX `IX_Streets_CityId` ON `Streets` (`CityId`);
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (10ms) [Parameters=[@p0='08d996c3-9074-4359-8d0f-e9df957a75d4', @p1='Berlin' (Size = 4000)], CommandType='Text', CommandTimeout='30']
INSERT INTO `Cities` (`Id`, `Name`)
VALUES (@p0, @p1);
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[@p2='08d996c3-9080-47d8-8cb3-5b8ee8c7e720', @p3='08d996c3-9074-4359-8d0f-e9df957a75d4', @p4='Potsdamer Platz' (Size = 4000)], CommandType='Text', CommandTimeout='30']
INSERT INTO `Streets` (`Id`, `CityId`, `Name`)
VALUES (@p2, @p3, @p4);
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 6.0.0-dev initialized 'Context' using provider 'Pomelo.EntityFrameworkCore.MySql:6.0.0-rc.1' with options: SensitiveDataLoggingEnabled DetailedErrorsEnabled ServerVersion 8.0.25-mysql
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT `t`.`Id`, `t`.`Name`, `s`.`Id`, `s`.`CityId`, `s`.`Name`
FROM (
SELECT `c`.`Id`, `c`.`Name`
FROM `Cities` AS `c`
ORDER BY `c`.`Id`
LIMIT 1
) AS `t`
LEFT JOIN `Streets` AS `s` ON `t`.`Id` = `s`.`CityId`
ORDER BY `t`.`Id`
该代码按预期工作,您可以根据需要一次性保存尽可能多的不同实体。
如果同一个Street
可以是多个City
实体的一部分,这意味着您想要多对多关系,我也可以为您发布一些该场景的示例代码。