EF核心:在同一张表之间定义1对1和1对许多

时间:2019-01-10 20:41:12

标签: c# entity-framework-core ef-core-2.1 ef-core-2.2

我有两个表,为了便于讨论,我们将它们称为ProfileSessionProfile具有当前活动的会话(可选),并且所有会话都必须链接到配置文件(即使是未活动的会话)。

table definition

因此,我们在Session上的ProfileCurrentSessionId之间是一对一的关系,在ProfileSession之间是一对多的关系

问题是如何先在Entity Framework代码中构建它?

我有两个实体

public class Profile
{
    public Guid Id { get; set; }

    public Session CurrentSession { get; set; }
}

public class Session
{
    public Guid Id { get; set; }
}

和两种类型的配置

public class ProfileTypeConfiguration : IEntityTypeConfiguration<Profile>
{
    public void Configure(EntityTypeBuilder<Profile> builder)
    {
        builder.ToTable("Profile");
        builder.HasKey(x => x.Id);

        builder.HasOne(x => x.CurrentSession)
            .WithOne()
            .HasForeignKey<Profile>("CurrentSessionId")
            .HasConstraintName("FK_CurrentSession_Profile")
            .IsRequired(false);
    }
}

public class SessionTypeConfiguration : IEntityTypeConfiguration<Session>
{
    public void Configure(EntityTypeBuilder<Session> builder)
    {
        builder.ToTable("Session");
        builder.HasKey(x => x.Id);

        builder.HasOne<Profile>()
            .WithMany()
            .HasForeignKey("ProfileId")
            .HasConstraintName("FK_Profile_CurrentSession")
            .IsRequired();
    }
}

所有这些操作均使用正确的列和外键按预期生成数据库模式。当我尝试将配置文件插入数据库时​​出现问题

var profile = new Profile
{
    Id = Guid.NewGuid(),
    CurrentSession = new Session
    {
         Id = Guid.NewGuid()
    }
};

ctx.Profiles.Add(profile);
ctx.SaveChanges();

这时我得到SqlException的话

  

INSERT语句与FOREIGN KEY约束“ FK_Profile_CurrentSession”冲突

在探查器中查找,插入不包括Profile记录,它只是试图插入Session

exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Session] ([Id], [ProfileId])
VALUES (@p0, @p1);
',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='AE96BD5F-FB0D-4E02-8E97-FBEFE4EF1382',@p1='00000000-0000-0000-0000-000000000000'

我想做的是可能的吗?应该用其他方式定义它吗?

  • EF核心版本:2.2.1
  • 数据库提供程序:Microsoft.EntityFrameworkCore.SqlServer
  • 操作系统:Windows 10

1 个答案:

答案 0 :(得分:0)

我能够通过明确定义键,然后在设置当前会话之前分别创建配置文件和会话来使其工作。

实体

public class Profile
{
    public Guid Id { get; set; }
    public Guid? CurrentSessionId { get; set; }
    public Session CurrentSession { get; set; }
}

public class Session
{
    public Guid Id { get; set; }
    public Guid ProfileId { get; set; }
}

类型配置

public class ProfileTypeConfiguration : IEntityTypeConfiguration<Profile>
{
    public void Configure(EntityTypeBuilder<Profile> builder)
    {
        builder.ToTable("Profile");
        builder.HasKey(x => x.Id);

        builder.HasMany<Session>()
            .WithOne()
            .HasForeignKey(e => e.ProfileId)
            .HasConstraintName("FK_Profile_CurrentSession")
            .IsRequired();

        builder.HasOne(x => x.CurrentSession)
            .WithOne()
            .HasForeignKey<Profile>("CurrentSessionId")
            .HasConstraintName("FK_CurrentSession_Profile")
            .IsRequired(false);
    }
}

public class SessionTypeConfiguration : IEntityTypeConfiguration<Session>
{
    public void Configure(EntityTypeBuilder<Session> builder)
    {
        builder.ToTable("Session");
        builder.HasKey(x => x.Id);
    }
}

程序。

var profileId = Guid.NewGuid();
var sessionId = Guid.NewGuid();

var profile = new Profile
{
    Id = profileId,
};

var session = new Session
{
    Id = sessionId,
    ProfileId = profileId
};

ctx.Profiles.Add(profile);
ctx.Sessions.Add(session);
ctx.SaveChanges();

profile.CurrentSession = session;
ctx.SaveChanges();

如果您尝试将会话直接应用于配置文件,它将创建循环依赖项,因此您必须先创建它们并保存。然后,设置电流并再次保存。