Невозможно определить таблицу без ПК - PullRequest
0 голосов
/ 13 сентября 2018

У меня есть таблица с именем AspNetUsers, которая является таблицей по умолчанию, созданной AspNetCore.Identity, я создал класс с именем User, который наследует IdentityUser и реализует дополнительные поля в AspNetUsers:

public class User : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
    public string LockoutMessage { get; set; }
    public string SessionId { get; set; }

    public virtual UserDetails UserDetail { get; set; }
}

затем я создал другой класс с именем UserDetails, мне не нужно PK в этой таблице, потому что в UserDetails мне нужно хранить сведения о пользователе, доступные в User, то есть AspNetUsers таблица:

public class UserDetails
{
    //public string Id { get; set; }
    public string Biography { get; set; }
    public string Country { get; set; }
    public string FacebookLink { get; set; }
    public string TwitterLink { get; set; }
    public string SkypeLink { get; set; }

    public string UserId { get; set; }
    public virtual User User { get; set; }
}

Теперь, если я раскомментирую свойство Id, миграция будет работать хорошо, но мне не нужен Id, поэтому я прокомментировал свойство и выполнил следующую команду:

add-migration Initial-Migration -context DemoAppContext
update-database

внутри класса DemoAppContext, который я сказал EF для реализации FK в UserDetails:

public class DemoAppContext : IdentityDbContext<User>
{
    public DemoAppContext(DbContextOptions<DemoAppContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<User>(entity =>
        {
            entity.HasOne(d => d.UserDetail)
                  .WithOne(p => p.User)
                  .HasForeignKey<UserDetails>(x => x.UserId);
        });
    }

    public DbSet<UserDetails> UserDetails { get; set; }
}

после команды Add-Migration я получаю эту ошибку:

Тип сущности 'UserDetails' требует определения первичного ключа.

Как я уже сказал, если я закомментировал, Id все работает хорошо, но мне не нужно PK на UserDetails.

1 Ответ

0 голосов
/ 14 сентября 2018

Как я уже сказал, если я закомментировал Id, все работает хорошо, но мне не нужен PK для UserDetails

Если я правильно понимаю, вы просто не хотите добавлять дополнительный столбец (например, Id или UserDetailsId), установленный в качестве PK. Таблица UserDetails, которую вы хотите создать, будет иметь UserId, которая ссылается на таблицу User, а UserId будет одновременно выполнять роль PK и FK.

На самом деле нет необходимости иметь свойство Id для объекта UserDetails. Так почему ваш код не работает? Причина в том, что вы смешали зависимую сущность и основную сущность.

Прототип HasForeignKey<>() метода :

public virtual ReferenceReferenceBuilder<TEntity,TRelatedEntity> HasForeignKey<TDependentEntity> 
    (
        Expression<Func<TDependentEntity,object>> foreignKeyExpression
    ) 
    where TDependentEntity : class;

Обратите внимание, что общий параметр HasForeignKey<TDependentEntity>() представляет зависимую сущность.

А вот ваш код:

builder.Entity<User>(entity =>
{
    entity.HasOne(d => d.UserDetail)
            .WithOne(p => p.User)
        .HasForeignKey<UserDetails>(x => x.UserId);
});

Видите это? В вашем коде entity здесь - User, который является основным объектом, а не зависимым объектом. Чтобы исправить это, измените свой код, как показано ниже:

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<User>(entity =>
    {
        entity.HasOne(u => u.UserDetail).WithOne(d => d.User);
    });

    builder.Entity<UserDetails>(entity =>
    {
        // set the UserId as key
        entity.HasKey(d=>d.UserId);

        // the relationship between `UserDetails : User`  is  1-to-1
        entity.HasOne(d=>d.User).WithOne(u=>u.UserDetail)
            // set column `UserId` as the FK for the dependent entity , i.e. , the `UserDetails` .
            .HasForeignKey<UserDetails>(u=>u.UserId); 
    });
}

Будет сгенерирована таблица UserDetails с столбцом UserId, установленным как PrimaryKey и ForeignKey одновременно:

CREATE TABLE [dbo].[UserDetails] (
    [Biography]    NVARCHAR (MAX) NULL,
    [Country]      NVARCHAR (MAX) NULL,
    [FacebookLink] NVARCHAR (MAX) NULL,
    [TwitterLink]  NVARCHAR (MAX) NULL,
    [SkypeLink]    NVARCHAR (MAX) NULL,
    [UserId]       NVARCHAR (450) NOT NULL,
    CONSTRAINT [PK_UserDetails] PRIMARY KEY CLUSTERED ([UserId] ASC),
    CONSTRAINT [FK_UserDetails_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);

Кстати, в SQL Server Object Explorer Visual Studio, похоже, есть ошибка (см. мой вопрос здесь ), приводящая к ошибке, что мы не можем видеть уже существующие противоречия FK.

Однако мы можем доказать это, попытавшись вставить строку с несуществующим UserId:

insert into UserDetails 
    (Biography,UserId) 
values 
    ('hello,wrold','here-is-a-non-existing-user-id')

Будет выдано следующее сообщение, как и ожидалось:

Сообщение 547, Уровень 16, Состояние 0, Строка 1

Оператор INSERT конфликтовал с ограничением FOREIGN KEY "FK_UserDetail_AspNetUsers_UserId". Конфликт произошел в базе данных «App-EFCore-FK-Test», таблице «dbo.AspNetUsers», столбце «Id».

Оператор был расторгнут.

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