Подтвердить что ты не робот

Первоначальное понимание атрибута ForeignKey в коде структуры сущности

Для получения дополнительной информации см. следующий пост:

Структура сущности от одного до нуля или одна связь без свойства навигации

Я всегда думал, что ForeignKey используется, чтобы показать, какое свойство принадлежит классу, содержащему ForeignKey, который определил свойство навигации, например.

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("DeferredDataId")]
    public virtual DeferredData DeferredData { get; set; }
}

Однако я обнаружил на связанном сообщении, что это неправильно, и что, поскольку первичный ключ DeferredData был вызван Id, мне действительно нужно:

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }
}

то есть. ForeignKey используется для указания на другой класс.

Затем я приступил к изменению некоторых других ссылок:

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }

    public int? SignedOffById { get; set; }
    [ForeignKey("UserId")]
    public virtual UserProfile SignedOffBy { get; set; }
}

Однако это не удалось. Оказавшись на этом, ForeignKey нужно указать на Id в классе MemberDataSet.

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }

    public int? SignedOffById { get; set; }
    [ForeignKey("SignedOffById")]
    public virtual UserProfile SignedOffBy { get; set; }
}

Я предполагаю, что это связано с тем, что эта вторая взаимосвязь одна для многих, в то время как первая была одна к нулю или одна, и что фактически основной конец отношения отличается, но я бы признателен за некоторую ясность в отношении этого/ссылок на хорошие статьи, поэтому я могу понять, что происходит и что делает ForeignKey.

Я также искал ясность в приведенном выше примере того, как public int? DeferredDataId { get; set; } вписывается в уравнение, поскольку оно явно не связано с DeferredData. Я счастлив, что это будет соответствовать договоренности, но как я могу это прямо сказать, например, если у него другое имя? В примерах, которые я видел в этом разговоре об использовании атрибута ForeignKey, но это не может быть ответом во всех случаях выше!

Вся помощь очень ценится - нужно понять проблему, а не исправить конкретную проблему, так как у меня много ссылок в моей модели, поэтому нужно установить, какой подход взять с каждой.

Спасибо.

Edit

Добавлены другие классы, которые помогут:

public class DeferredData
{

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    //other properties
}

public class UserProfile
{

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    //other properties
}
4b9b3361

Ответ 1

Требуемая сторона отношения 1..0 MemberDataSet не должна иметь FK до DeferredData. Вместо этого DeferredData PK также должен быть FK до MemberDataSet (известный как общий первичный ключ)

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public virtual DeferredData DeferredData { get; set; }
}

public class DeferredData
{
    // DeferredData.Id is both the PK and a FK to MemberDataSet
    [Key]
    [DatabaseGenerated( DatabaseGeneratedOption.None )]
    [ForeignKey( "MemberDataSet" )]
    public int Id { get; set; }

    [Required]
    public virtual MemberDataSet MemberDataSet { get; set; }
}

Fluent API:

modelBuilder.Entity<MemberDataSet>()
    .HasOptional( mds => mds.DeferredData )
    .WithRequired()
    .WillCascadeOnDelete();

Ответ 2

Я думаю, что вы были правы (при условии, что я правильно понимаю вас). [ForeignKeyAttribute] используется для соответствующего внешнего ключа. Не на основном ключе вашего связанного объекта.

This is my object, and the foreign key is DeferredDataId

Ни один Id внутри вашего объекта не является внешним ключом (его первичный ключ), а Id связанного объекта является внешним ключом (это первичный ключ другой стороны отношения)

Надеюсь, я правильно тебя понял:) Потому что я не уверен.

Ответ 3

Я думаю, что твоя оригинальная идея была правильной, с одним небольшим исключением. Поместив внешний ключ на MemberDataSet, вы подразумеваете, что вам нужны отношения "нуль-один-ко-многим".

В вашем примере MemberDataSet.DeferredData является необязательным, а DeferredData может ссылаться на многие экземпляры MemberDataSet.

В свободном синтаксисе это выражается:

modelBuilder.Entity<MemberDataSet>()
    .HasOptional(dataSet => dataSet.DeferredData)
    .WithMany()
    .HasForeignKey(deferredData => deferredData.DeferredDataId);

Чтобы сделать это свойство "один к нулю" или "один", вы можете поместить в столбец MemberDataSet DeferredDataId ограничение уникальное (где не пустое). Это означало бы, что объект DeferredData может ссылаться только на один объект MemberDataSet.

CREATE UNIQUE INDEX unique_MemberDataSet_DeferredDataId ON MemberDataSet(DeferredDataId) WHERE DeferredDataId IS NOT NULL

Примечание: Этот тип отфильтрованного ключа доступен только в SQL Server 2008 и выше.