EF核心,是否应该在课堂上添加外键ID?

时间:2020-03-13 00:53:24

标签: c# .net-core ef-core-3.1

我从其他站点阅读了一些教程,有的添加了外键ID,有的没有添加,而另一些则添加了虚拟。

例如:

class Class
{
    public int Id { get; set; }
    public string ClassName { get; set; }
    public List<Student> Students { get; set; }
}

class Student
{
    public int Id { get; set; }
    public string StudentName { get; set; }
    public Class class { get; set; }
}

Student类中,有的在Class类内部使用了ClassId上的虚拟,而有的在Student类中使用了import XCTest class TrimCharacters: XCTestCase { func testExample() throws { let string = "abcbaHello, World!ccbbaa" let charactersToTrim = CharacterSet(charactersIn: "abc,") XCTAssertEqual(string.trimmingCharacters(in: charactersToTrim), "Hello, World!") } }

最佳做法是什么?我正在将EF Core 3与.NET Core 3.1(最新版本)一起使用

2 个答案:

答案 0 :(得分:2)

该模式称为“ Shadow-property”。假设我们要通过Students获得所有ClassId

使用Shadow Property,有2个访问数据的选项:

context.Classes.Include(x => x.Students).FirstOrDefault(x => x.Id == classId)?.Students;

//we have to know the name of foreign key from db.
context.Students.Where(x => EF.Property<int>(x, "ClassId") == classId).ToList(); 

使用显式外键,代码为:

context.Students.Where(x => x.ClassId == classId).ToList();

第二和第三代码避免使用join,看起来更好的性能。但是哪一种是2种风格中最好的?这确实取决于项目和编码风格的偏好。

尽管第二种样式易于设置:

class MyContext : DbContext
{
    public DbSet<Student> Students { get; set; }
    public DbSet<Class> Classes { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Add the shadow property to the model
        modelBuilder.Entity<Student>()
            .Property<int>("ClassId");

        // Use the shadow property as a foreign key
        modelBuilder.Entity<Student>()
            .HasOne(p => p.Class)
            .WithMany(b => b.Students)
            .HasForeignKey("ClassId");
    }
}

这里有2个参考文献:

  1. https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties

  2. https://docs.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key

答案 1 :(得分:0)

在EF的上下文中,将属性标记为虚拟允许EF使用延迟加载来加载它。为了使延迟加载正常工作,EF必须创建一个代理对象,该代理对象将使用一个在首次访问该引用实体时加载该引用实体的实现来覆盖您的虚拟属性。如果您未将属性标记为虚拟,则延迟加载将无法使用。

对于Web应用程序,最好不要使用延迟加载,因为延迟加载可能会提取大量数据。

假设您要从对象/类生成数据库模型/关系(使用EF核心的代码优先迁移),最重要的部分是实体的映射配置(在模型属性上使用注释或使用Fluent API)。

如果您对“ Id”属性格式没有任何特定要求,只需将其设置为由数据库生成即可。

在您的情况下,我将通过以下方式进行配置:

class Class
{
    public int ClassId { get; set; }
    public string ClassName { get; set; }
    public ICollection<Student> Students { get; set; }
}

class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }
    public int ClassId { get; set; }
    public Class class { get; set; }
}

而且,使用Fluent API配置映射的一种方法可能是:

public class StudentConfiguration : IEntityTypeConfiguration<Student>
{
    public void Configure(EntityTypeBuilder<Student> builder)
    {
        builder
             .HasKey(s => s.StudentId);

        builder
            .Property(s => s.StudentId)
            .UseIdentityColumn();

        builder
            .Property(c => c.StudentName)
            .HasMaxLength(<studentName_maxLength>);

        builder
            .HasOne(s => s.Class)
            .WithMany(c => c.Students)
            .HasForeignKey(s => s.ClassId);

        builder
            .ToTable("Student");
    }
}

public class ClassConfiguration : IEntityTypeConfiguration<Class>
{
    public void Configure(EntityTypeBuilder<Class> builder)
    {
        builder
             .HasKey(c => c.ClassId);

        builder
            .Property(c => c.ClassId)
            .UseIdentityColumn();   

        builder
            .Property(c => c.ClassName)
            .HasMaxLength(<className_maxLength>);

        builder
            .HasMany(c => c.Students)
            .WithOne(s => s.Class);

        builder
            .ToTable("Class");
    }
}

有关配置Fluent API一对多映射的更多详细信息,here