EF Core 2.1 - 使用流畅时重复关系 API
EF Core 2.1 - Duplicate relationships when use fluent API
我使用 .NET Core 2.1 和 EF Core 开发了一个 Web API。
但是我的 ApplicationDbContext 有一个我不明白的问题。
我有 2 tables(用户和配置文件,一对多),不需要用户 table 中的外键配置文件。
使用 Fluent API,当我声明我的关系时,ef core 在同一引用上创建重复的外键,但为什么呢?
这是我的用户模型:
public class UserModel
{
public long Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public DateTime DateAdded { get; set; }
public DateTime? DateUpdated { get; set; }
public DateTime? DateLastConnection { get; set; }
public long? ProfileId { get; set; }
public ProfileModel Profile { get; set; }
}
public class UserModelConfiguration : IEntityTypeConfiguration<UserModel>
{
public void Configure(EntityTypeBuilder<UserModel> builder)
{
builder.ToTable("USR_USER");
builder.Property(table => table.Id).HasColumnName("ID").HasColumnType("bigint").UseSqlServerIdentityColumn();
builder.Property(table => table.Username).HasColumnName("USERNAME").HasColumnType("nvarchar(20)").HasMaxLength(20).IsRequired();
builder.Property(table => table.Password).HasColumnName("PASSWD").HasColumnType("nvarchar(200)").HasMaxLength(200).IsRequired();
builder.Property(table => table.DateAdded).HasColumnName("DATE_ADDED").HasColumnType("datetime").IsRequired().IsRequired();
builder.Property(table => table.DateUpdated).HasColumnName("DATE_UPDATED").HasColumnType("datetime");
builder.Property(table => table.DateLastConnection).HasColumnName("LAST_CONNECTION").HasColumnType("datetime");
builder.Property(table => table.ProfileId).HasColumnName("PROFILE_ID").HasColumnType("bigint");
builder.HasKey(table => table.Id);
builder.HasAlternateKey(table => table.Username);
builder.HasOne<ProfileModel>()
.WithMany(p => p.Users)
.HasForeignKey(u => u.ProfileId);
}
}
这是我的 ProfileModel:
public class ProfileModel
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<UserModel> Users { get; set; }
public ICollection<ProfileRoleModel> ProfileRoles { get; set; }
}
public class ProfileModelConfiguration : IEntityTypeConfiguration<ProfileModel>
{
public void Configure(EntityTypeBuilder<ProfileModel> builder)
{
builder.ToTable("USR_PROFILE");
builder.Property(p => p.Id).HasColumnName("ID").HasColumnType("bigint").UseSqlServerIdentityColumn();
builder.Property(p => p.Name).HasColumnName("PROFILE_NAME").HasColumnType("nvarchar(20)").HasMaxLength(20).IsRequired();
builder.Property(p => p.Description).HasColumnName("PROFILE_DESCRIPTION").HasColumnType("nvarchar(200)").HasMaxLength(200).IsRequired();
builder.HasKey(p => p.Id);
}
}
这是我的应用程序上下文:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<UserModel> Users { get; set; }
public DbSet<ProfileModel> Profiles { get; set; }
public DbSet<ProfileRoleModel> ProfileRoles { get; set; }
public DbSet<RoleModel> Roles { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new UserModelConfiguration());
modelBuilder.ApplyConfiguration(new ProfileModelConfiguration());
modelBuilder.ApplyConfiguration(new ProfileRoleModelConfiguration());
modelBuilder.ApplyConfiguration(new RoleModelConfiguration());
}
}
迁移结果,如您所见,有两个外键。
因此,当我查询我的 DbSet 用户时,我有一个 sql 错误 'Unknown column ProfileId1'
CREATE TABLE [USR_PROFILE] (
[ID] bigint NOT NULL IDENTITY,
[PROFILE_NAME] nvarchar(20) NOT NULL,
[PROFILE_DESCRIPTION] nvarchar(200) NOT NULL,
CONSTRAINT [PK_USR_PROFILE] PRIMARY KEY ([ID])
);
GO
CREATE TABLE [USR_USER] (
[ID] bigint NOT NULL IDENTITY,
[USERNAME] nvarchar(20) NOT NULL,
[PASSWD] nvarchar(200) NOT NULL,
[DATE_ADDED] datetime NOT NULL,
[DATE_UPDATED] datetime NULL,
[LAST_CONNECTION] datetime NULL,
[PROFILE_ID] bigint NULL,
[ProfileId1] bigint NULL,
CONSTRAINT [PK_USR_USER] PRIMARY KEY ([ID]),
CONSTRAINT [AK_USR_USER_USERNAME] UNIQUE ([USERNAME]),
CONSTRAINT [FK_USR_USER_USR_PROFILE_PROFILE_ID] FOREIGN KEY ([PROFILE_ID]) REFERENCES [USR_PROFILE] ([ID]) ON DELETE NO ACTION,
CONSTRAINT [FK_USR_USER_USR_PROFILE_ProfileId1] FOREIGN KEY ([ProfileId1]) REFERENCES [USR_PROFILE] ([ID]) ON DELETE NO ACTION
);
GO
我的另一个 DbSet 也有同样的问题,但我认为这是一个类似的问题。
我的配置基于此文档Fully Defined Relationship
因为你有导航属性
public ProfileModel Profile { get; set; }
但配置流畅
builder.HasOne<ProfileModel>()
您是在告诉英孚,它不是该关系的一部分。因此 EF 通常将其映射到另一个具有自动生成的 FK 名称的单独关系。
您应该始终使用 Has
/ With
方法重载,它们表示关系相应端的导航 属性 的 presence/absence。
在您的情况下,将上面的内容替换为
builder.HasOne(u => u.Profile)
问题就迎刃而解了
我使用 .NET Core 2.1 和 EF Core 开发了一个 Web API。 但是我的 ApplicationDbContext 有一个我不明白的问题。 我有 2 tables(用户和配置文件,一对多),不需要用户 table 中的外键配置文件。
使用 Fluent API,当我声明我的关系时,ef core 在同一引用上创建重复的外键,但为什么呢?
这是我的用户模型:
public class UserModel
{
public long Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public DateTime DateAdded { get; set; }
public DateTime? DateUpdated { get; set; }
public DateTime? DateLastConnection { get; set; }
public long? ProfileId { get; set; }
public ProfileModel Profile { get; set; }
}
public class UserModelConfiguration : IEntityTypeConfiguration<UserModel>
{
public void Configure(EntityTypeBuilder<UserModel> builder)
{
builder.ToTable("USR_USER");
builder.Property(table => table.Id).HasColumnName("ID").HasColumnType("bigint").UseSqlServerIdentityColumn();
builder.Property(table => table.Username).HasColumnName("USERNAME").HasColumnType("nvarchar(20)").HasMaxLength(20).IsRequired();
builder.Property(table => table.Password).HasColumnName("PASSWD").HasColumnType("nvarchar(200)").HasMaxLength(200).IsRequired();
builder.Property(table => table.DateAdded).HasColumnName("DATE_ADDED").HasColumnType("datetime").IsRequired().IsRequired();
builder.Property(table => table.DateUpdated).HasColumnName("DATE_UPDATED").HasColumnType("datetime");
builder.Property(table => table.DateLastConnection).HasColumnName("LAST_CONNECTION").HasColumnType("datetime");
builder.Property(table => table.ProfileId).HasColumnName("PROFILE_ID").HasColumnType("bigint");
builder.HasKey(table => table.Id);
builder.HasAlternateKey(table => table.Username);
builder.HasOne<ProfileModel>()
.WithMany(p => p.Users)
.HasForeignKey(u => u.ProfileId);
}
}
这是我的 ProfileModel:
public class ProfileModel
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<UserModel> Users { get; set; }
public ICollection<ProfileRoleModel> ProfileRoles { get; set; }
}
public class ProfileModelConfiguration : IEntityTypeConfiguration<ProfileModel>
{
public void Configure(EntityTypeBuilder<ProfileModel> builder)
{
builder.ToTable("USR_PROFILE");
builder.Property(p => p.Id).HasColumnName("ID").HasColumnType("bigint").UseSqlServerIdentityColumn();
builder.Property(p => p.Name).HasColumnName("PROFILE_NAME").HasColumnType("nvarchar(20)").HasMaxLength(20).IsRequired();
builder.Property(p => p.Description).HasColumnName("PROFILE_DESCRIPTION").HasColumnType("nvarchar(200)").HasMaxLength(200).IsRequired();
builder.HasKey(p => p.Id);
}
}
这是我的应用程序上下文:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<UserModel> Users { get; set; }
public DbSet<ProfileModel> Profiles { get; set; }
public DbSet<ProfileRoleModel> ProfileRoles { get; set; }
public DbSet<RoleModel> Roles { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new UserModelConfiguration());
modelBuilder.ApplyConfiguration(new ProfileModelConfiguration());
modelBuilder.ApplyConfiguration(new ProfileRoleModelConfiguration());
modelBuilder.ApplyConfiguration(new RoleModelConfiguration());
}
}
迁移结果,如您所见,有两个外键。 因此,当我查询我的 DbSet 用户时,我有一个 sql 错误 'Unknown column ProfileId1'
CREATE TABLE [USR_PROFILE] (
[ID] bigint NOT NULL IDENTITY,
[PROFILE_NAME] nvarchar(20) NOT NULL,
[PROFILE_DESCRIPTION] nvarchar(200) NOT NULL,
CONSTRAINT [PK_USR_PROFILE] PRIMARY KEY ([ID])
);
GO
CREATE TABLE [USR_USER] (
[ID] bigint NOT NULL IDENTITY,
[USERNAME] nvarchar(20) NOT NULL,
[PASSWD] nvarchar(200) NOT NULL,
[DATE_ADDED] datetime NOT NULL,
[DATE_UPDATED] datetime NULL,
[LAST_CONNECTION] datetime NULL,
[PROFILE_ID] bigint NULL,
[ProfileId1] bigint NULL,
CONSTRAINT [PK_USR_USER] PRIMARY KEY ([ID]),
CONSTRAINT [AK_USR_USER_USERNAME] UNIQUE ([USERNAME]),
CONSTRAINT [FK_USR_USER_USR_PROFILE_PROFILE_ID] FOREIGN KEY ([PROFILE_ID]) REFERENCES [USR_PROFILE] ([ID]) ON DELETE NO ACTION,
CONSTRAINT [FK_USR_USER_USR_PROFILE_ProfileId1] FOREIGN KEY ([ProfileId1]) REFERENCES [USR_PROFILE] ([ID]) ON DELETE NO ACTION
);
GO
我的另一个 DbSet 也有同样的问题,但我认为这是一个类似的问题。
我的配置基于此文档Fully Defined Relationship
因为你有导航属性
public ProfileModel Profile { get; set; }
但配置流畅
builder.HasOne<ProfileModel>()
您是在告诉英孚,它不是该关系的一部分。因此 EF 通常将其映射到另一个具有自动生成的 FK 名称的单独关系。
您应该始终使用 Has
/ With
方法重载,它们表示关系相应端的导航 属性 的 presence/absence。
在您的情况下,将上面的内容替换为
builder.HasOne(u => u.Profile)
问题就迎刃而解了