EF Core中使用Fluent API实现一对一关系

7

我正在使用EF Core 2.1

如何在EF Core中映射一对一关系。我有客户(Customer)课程(Course)领域实体,其中一个客户将拥有一门课程。

这是我的Customer & CoursePOCO的样子。

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }

}

public class Course
{
    public int Id { get; set; }
    public string CouseName { get; set; }
    public virtual Customer Customer { get; set; }
}

我正在使用FluentAPI。
 public class CourseConfiguration : IEntityTypeConfiguration<Course>
{
    public void Configure(EntityTypeBuilder<Parent> builder)
    {
        builder.HasKey(x => x.Customer.Id) //not allowing -> throws error
        //The properties expression 'x => Convert(x.Customer.Id, Object)' is not valid. 
        // The expression should represent a simple property access: 't => t.MyProperty'. 
        // When specifying multiple properties use an anonymous type: 't => new { t.MyProperty1, t.MyProperty2 }'. 
        // Parameter name: propertyAccessExpression
    }
}

由于是一对一的关系,我不想在联系人中创建额外的键(FK -CustomerId),

主要要求:- 我想将 Id(在课程中)定义为 PK + FK,并且在这个关系中客户是父实体。

例如,如果我是基于配置的迁移,我会按照以下方式操作:

public class Course
{
    [Key]
    [ForeignKey("Customer")]
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Customer Customer { get; set; }
 }

我想用EF Core的Fluent API来实现同样的事情,你能帮我翻译一下吗?

谢谢!


只是好奇,为什么你想在课程上将客户fk作为ID?课程是一些通用的东西..我认为更好的模型应该是一个客户拥有一个课程,你不这样认为吗?这样你的模型会变得更简单,并且如果以后你决定将你的课程与其他东西联系起来,你也会很安全。 - jpgrassi
2个回答

10
如其他答案所指出的,关键点是使用HasForeignKey<>()方法配置外键。 但要注意外键应该设置在从属实体上,而不是主实体上。 具体步骤如下:
Course添加一个导航属性Customer
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Course Course {get;set;} 
}

现在将 Course.Id 设置为引用 Customer.IdFK

public class AppDbContext : DbContext
{
    public AppDbContext (DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<Customer>(entity=>
        {
            entity.HasOne(customer=>customer.Course)
                .WithOne(course=> course.Customer)
                .HasForeignKey<Course>(course=>course.Id); 
        });
    }

    public DbSet<App.Models.Customer> Customer { get; set; }
    public DbSet<App.Models.Course> Courses{ get; set; }
}

生成的 SQL 脚本如下:
CREATE TABLE [Customer] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NULL,
    CONSTRAINT [PK_Customer] PRIMARY KEY ([Id])
);

GO

CREATE TABLE [Courses] (
    [Id] int NOT NULL,
    [CouseName] nvarchar(max) NULL,
    CONSTRAINT [PK_Courses] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Courses_Customer_Id] FOREIGN KEY ([Id]) REFERENCES [Customer] ([Id]) ON DELETE CASCADE
);

GO

感谢您强调主要实体点,但仍未解决主要需求。我不想将Id和Customer分别作为PK和FK,而是希望在课程中将Id作为PK和FK。 - Kgn-web
@Kgn-web 我没有分别创建PK和FK。Course.Id同时作为PK和FK。 - itminus
@Kgn-web,您可以检查上面的SQL脚本(由dotnet ef migrations script生成)以确认Courses.Id同时作为PK和FK。 - itminus
检查正在进行中,请给我一些时间。谢谢。 - Kgn-web
很酷。是的。你的帖子满足了我的需求。谢谢。 - Kgn-web
感谢您的修改。但是,在我看来,这次修改是不正确的。因此,我将其回滚。如果您认为我有错,请纠正我 :) - itminus

4
类似下面的代码可以帮助你。使用HasOne方法与WithOne链接可以建立一对一的关系:
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }

}

public class Course
{
    public int Id { get; set; }
    public string CourseName { get; set; }
    public int CustomerId {get;set;}
    public virtual Customer Customer { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Course>()
        .HasOne(a => a.Customer)
        .WithOne(b => b.Course)
        .HasForeignKey<Course>(b => b.CustomerId);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接