EF Core - 运行 Scaffold-DbContext 后尽管有外键,但类中仍缺少相关实体

Chr*_*ris 8 c# sql sql-server entity-framework-core ef-core-6.0

在 SQL Server 数据库中,我有两个几乎相同的表TBL_1和TBL_2。以下是两个表的创建脚本:

TBL_1:

CREATE TABLE [dbo].[TBL_1](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](100) NOT NULL,
    [value_type_ID] [int] NOT NULL,
    [description] [nvarchar](150) NOT NULL,
 CONSTRAINT [PK_TBL_1] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[TBL_1] ADD  CONSTRAINT [DF__TBL_1__param__40F9A68C]  DEFAULT ('-') FOR [name]
GO

ALTER TABLE [dbo].[TBL_1] ADD  CONSTRAINT [DF_TBL_1_description]  DEFAULT ('-') FOR [description]
GO

ALTER TABLE [dbo].[TBL_1]  WITH CHECK ADD  CONSTRAINT [TBL_1_TBL_value_types] FOREIGN KEY([value_type_ID])
REFERENCES [dbo].[TBL_Value_Type_Definition] ([value_type_ID])
GO

ALTER TABLE [dbo].[TBL_1] CHECK CONSTRAINT [TBL_1_TBL_value_types]
GO
Run Code Online (Sandbox Code Playgroud)

TBL_2:

CREATE TABLE [dbo].[TBL_2](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](100) NOT NULL,
    [value_type_ID] [int] NOT NULL,
 CONSTRAINT [PK_TBL_2] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[TBL_2] ADD  CONSTRAINT [DF_TBL_2_name]  DEFAULT ('-') FOR [name]
GO

ALTER TABLE [dbo].[TBL_2]  WITH CHECK ADD  CONSTRAINT [TBL_2_TBL_value_types] FOREIGN KEY([value_type_ID])
REFERENCES [dbo].[TBL_Value_Type_Definition] ([value_type_ID])
GO

ALTER TABLE [dbo].[TBL_2] CHECK CONSTRAINT [TBL_2_TBL_value_types]
GO
Run Code Online (Sandbox Code Playgroud)

执行Scaffold-DbContext后,为这两个表生成了以下类:

public partial class Tbl2
{
    public Tbl2()
    {
        Tbl2Translations = new HashSet<Tbl2Translation>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public int ValueTypeId { get; set; }

    public virtual ICollection<Tbl2Translation> Tbl2Translations { get; set; }
}

public partial class Tbl1
{
    public Tbl1()
    {
        Tbl1Translations = new HashSet<Tbl1Translation>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public int ValueTypeId { get; set; }
    public string Description { get; set; }

    public virtual TblValueTypeDefinition ValueType { get; set; }
    public virtual ICollection<Tbl1Translation> Tbl1Translations { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

ValueType由于某种原因,为 生成了相关项Tbl1,但没有为 生成了相关项Tbl2。我已经比较了数据库中的表,但我找不到任何明显的原因来解释ValueType为什么Tbl2. 这非常令人沮丧,因为我没有调试这个问题的起点,所以基本上感觉就像大海捞针一样。这是生成的TblValueTypeDefinition类:

public partial class TblValueTypeDefinition
{
    public TblValueTypeDefinition()
    {
        Tbl2s = new HashSet<Tbl2>();
    }

    public int ValueTypeId { get; set; }
    public string Name { get; set; }
    public string Unit { get; set; }
    public string Type { get; set; }

    public virtual ICollection<Tbl2> Tbl2s { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是该表的创建脚本:

CREATE TABLE [dbo].[TBL_Value_Type_Definition](
    [value_type_ID] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](50) NOT NULL,
    [unit] [nvarchar](10) NOT NULL,
    [type] [nvarchar](10) NOT NULL,
 CONSTRAINT [PK_TBL_Value_Type_Definition] PRIMARY KEY CLUSTERED 
(
    [value_type_ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[TBL_Value_Type_Definition] ADD  DEFAULT ('-') FOR [name]
GO

ALTER TABLE [dbo].[TBL_Value_Type_Definition] ADD  DEFAULT ('-') FOR [unit]
GO

ALTER TABLE [dbo].[TBL_Value_Type_Definition] ADD  DEFAULT ('-') FOR [type]
GO
Run Code Online (Sandbox Code Playgroud)

其中一张表中缺少相关实体的原因可能是什么?

Jom*_*oma 1

表1表名有错误 REFERENCES [dbo].[TBL_value_types]而不是REFERENCES [dbo].[TBL_Value_Type_Definition]

错误

表2也有同样的错误(表名)。REFERENCES [dbo].[TBL_value_types]而不是参考文献[dbo].[TBL_Value_Type_Definition]

表已创建,但引用已损坏。不创建外键。 图1

固定代码 - Sql 脚本

CREATE TABLE [dbo].[TBL_Value_Type_Definition](
    [value_type_ID] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](50) NOT NULL,
    [unit] [nvarchar](10) NOT NULL,
    [type] [nvarchar](10) NOT NULL,
 CONSTRAINT [PK_TBL_Value_Type_Definition] PRIMARY KEY CLUSTERED 
(
    [value_type_ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[TBL_Value_Type_Definition] ADD  DEFAULT ('-') FOR [name]
GO

ALTER TABLE [dbo].[TBL_Value_Type_Definition] ADD  DEFAULT ('-') FOR [unit]
GO

ALTER TABLE [dbo].[TBL_Value_Type_Definition] ADD  DEFAULT ('-') FOR [type]
GO


CREATE TABLE [dbo].[TBL_1](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](100) NOT NULL,
    [value_type_ID] [int] NOT NULL,
    [description] [nvarchar](150) NOT NULL,
 CONSTRAINT [PK_TBL_1] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[TBL_1] ADD  CONSTRAINT [DF__TBL_1__param__40F9A68C]  DEFAULT ('-') FOR [name]
GO

ALTER TABLE [dbo].[TBL_1] ADD  CONSTRAINT [DF_TBL_1_description]  DEFAULT ('-') FOR [description]
GO

ALTER TABLE [dbo].[TBL_1]  WITH CHECK ADD  CONSTRAINT [TBL_1_TBL_value_types] FOREIGN KEY([value_type_ID])
REFERENCES [dbo].[TBL_Value_Type_Definition] ([value_type_ID])
GO

ALTER TABLE [dbo].[TBL_1] CHECK CONSTRAINT [TBL_1_TBL_value_types]
GO


CREATE TABLE [dbo].[TBL_2](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](100) NOT NULL,
    [value_type_ID] [int] NOT NULL,
 CONSTRAINT [PK_TBL_2] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[TBL_2] ADD  CONSTRAINT [DF_TBL_2_name]  DEFAULT ('-') FOR [name]
GO

ALTER TABLE [dbo].[TBL_2]  WITH CHECK ADD  CONSTRAINT [TBL_2_TBL_value_types] FOREIGN KEY([value_type_ID])
REFERENCES [dbo].[TBL_Value_Type_Definition] ([value_type_ID])
GO

ALTER TABLE [dbo].[TBL_2] CHECK CONSTRAINT [TBL_2_TBL_value_types]
GO
Run Code Online (Sandbox Code Playgroud)

图表确定

Microsoft.EntityFrameworkCore.Tools nuget 包中的Scaffold-DbContext

Scaffold-DbContext -Connection "Data Source=localhost; Initial Catalog=SO1;User ID=sa;Password=100;Encrypt=False" -Provider Microsoft.EntityFrameworkCore.SqlServer

生成代码

SO1Context.cs

using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace EfCoreMissingRelated
{
    public partial class SO1Context : DbContext
    {
        public SO1Context()
        {
        }

        public SO1Context(DbContextOptions<SO1Context> options)
            : base(options)
        {
        }

        public virtual DbSet<Tbl1> Tbl1s { get; set; } = null!;
        public virtual DbSet<Tbl2> Tbl2s { get; set; } = null!;
        public virtual DbSet<TblValueTypeDefinition> TblValueTypeDefinitions { get; set; } = null!;

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
                optionsBuilder.UseSqlServer("Data Source=localhost; Initial Catalog=SO1;User ID=sa;Password=100;Encrypt=False");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Tbl1>(entity =>
            {
                entity.ToTable("TBL_1");

                entity.Property(e => e.Id).HasColumnName("ID");

                entity.Property(e => e.Description)
                    .HasMaxLength(150)
                    .HasColumnName("description")
                    .HasDefaultValueSql("('-')");

                entity.Property(e => e.Name)
                    .HasMaxLength(100)
                    .HasColumnName("name")
                    .HasDefaultValueSql("('-')");

                entity.Property(e => e.ValueTypeId).HasColumnName("value_type_ID");

                entity.HasOne(d => d.ValueType)
                    .WithMany(p => p.Tbl1s)
                    .HasForeignKey(d => d.ValueTypeId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("TBL_1_TBL_value_types");
            });

            modelBuilder.Entity<Tbl2>(entity =>
            {
                entity.ToTable("TBL_2");

                entity.Property(e => e.Id).HasColumnName("ID");

                entity.Property(e => e.Name)
                    .HasMaxLength(100)
                    .HasColumnName("name")
                    .HasDefaultValueSql("('-')");

                entity.Property(e => e.ValueTypeId).HasColumnName("value_type_ID");

                entity.HasOne(d => d.ValueType)
                    .WithMany(p => p.Tbl2s)
                    .HasForeignKey(d => d.ValueTypeId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("TBL_2_TBL_value_types");
            });

            modelBuilder.Entity<TblValueTypeDefinition>(entity =>
            {
                entity.HasKey(e => e.ValueTypeId);

                entity.ToTable("TBL_Value_Type_Definition");

                entity.Property(e => e.ValueTypeId).HasColumnName("value_type_ID");

                entity.Property(e => e.Name)
                    .HasMaxLength(50)
                    .HasColumnName("name")
                    .HasDefaultValueSql("('-')");

                entity.Property(e => e.Type)
                    .HasMaxLength(10)
                    .HasColumnName("type")
                    .HasDefaultValueSql("('-')");

                entity.Property(e => e.Unit)
                    .HasMaxLength(10)
                    .HasColumnName("unit")
                    .HasDefaultValueSql("('-')");
            });

            OnModelCreatingPartial(modelBuilder);
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}
Run Code Online (Sandbox Code Playgroud)

表1.cs

using System;
using System.Collections.Generic;

namespace EfCoreMissingRelated
{
    public partial class Tbl1
    {
        public int Id { get; set; }
        public string Name { get; set; } = null!;
        public int ValueTypeId { get; set; }
        public string Description { get; set; } = null!;

        public virtual TblValueTypeDefinition ValueType { get; set; } = null!;
    }
}
Run Code Online (Sandbox Code Playgroud)

表格2.cs

using System;
using System.Collections.Generic;

namespace EfCoreMissingRelated
{
    public partial class Tbl2
    {
        public int Id { get; set; }
        public string Name { get; set; } = null!;
        public int ValueTypeId { get; set; }

        public virtual TblValueTypeDefinition ValueType { get; set; } = null!;
    }
}
Run Code Online (Sandbox Code Playgroud)

TblValueTypeDefinition.cs

using System;
using System.Collections.Generic;

namespace EfCoreMissingRelated
{
    public partial class TblValueTypeDefinition
    {
        public TblValueTypeDefinition()
        {
            Tbl1s = new HashSet<Tbl1>();
            Tbl2s = new HashSet<Tbl2>();
        }

        public int ValueTypeId { get; set; }
        public string Name { get; set; } = null!;
        public string Unit { get; set; } = null!;
        public string Type { get; set; } = null!;

        public virtual ICollection<Tbl1> Tbl1s { get; set; }
        public virtual ICollection<Tbl2> Tbl2s { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)