EF Core: определить от 1 до 1 и от 1 до многих между одними и теми же таблицами - PullRequest
0 голосов
/ 10 января 2019

У меня есть две таблицы, для аргумента давайте назовем их Profile и Session. Profile имеет текущий активный сеанс (необязательно), и все сеансы должны быть связаны с профилем (даже те, которые не активны).

table definition

Итак, мы имеем отношение 1 к 1 между Session и Profile на CurrentSessionId, а также отношение 1 к многим между Profile и Session.

Вопрос в том, как создать это в коде 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 Core версия: 2.2.1
  • Поставщик базы данных: Microsoft.EntityFrameworkCore.SqlServer
  • Операционная система: Windows 10

1 Ответ

0 голосов
/ 11 января 2019

Мне удалось заставить его работать, явно определив ключи, а затем создав отдельный профиль и сеанс перед настройкой текущего сеанса.

Сущности

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();

Если вы попытаетесь применить сеанс непосредственно к профилю, он создаст циклическую зависимость, поэтому вы должны сначала создать их и сохранить. Затем установите ток и сохраните снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...