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

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

Вот мой код первых классов:

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; }
}

public class DeferredData
{

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

    //other properties
}

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

Мне показалось, что я хотел указать следующее:

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

т.е. MemberDataSet имеет опцию DeferredData, но DeferredData имеет обязательный MemberDataSet, и эта связь должна каскадно удаляться.

Тем не менее, я тогда получаю ошибку:

Недопустимый атрибут ForeignKeyAttribute для свойства 'DeferredData' для типа 'MemberDataSet'. Имя внешнего ключа 'DeferredDataId' не найдено в зависимом типе 'DeferredData'. Значение Name должно быть разделенным запятыми списком имен свойств внешнего ключа.

редактировать

Почувствовав удовлетворение ответом Сэма ниже, я пошел дальше и изменил несколько других атрибутов ForeignKey. MemberDataSet имеет другое свойство, называемое SignedOffBy, которое является профилем пользователя. Ранее это выглядело так:

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; }

    public int? SignedOffById { get; set; }
    [ForeignKey("SignedOffId")]
    public virtual UserProfile SignedOffBy { 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; }
}

Однако теперь я получаю очень похожее сообщение об ошибке:

The ForeignKeyAttribute on property 'SignedOffBy' on type 'MemberDataSet' is not valid. The foreign key name 'UserId' was not found on the dependent type 'MemberDataSet'. The Name value should be a comma separated list of foreign key property names.

Разница здесь в том, что это отношение "многие к одному", т. Е. 1 пользователь может иметь несколько наборов подписанных данных. В этом ли разница? т.е. UserProfile теперь является основным объектом, поэтому ForeignKey находится в MemberDataSet?

Еще раз большое спасибо за любую помощь.

1 ответ

Решение

Ошибка

Недопустимый атрибут ForeignKeyAttribute для свойства 'DeferredData' для типа 'MemberDataSet'. Имя внешнего ключа 'DeferredDataId' не найдено в зависимом типе 'DeferredData'.

говорит вам, что именно не так.

DeferredData.Id is not DeferredData.DeferredDataId

Это твоя проблема.

Простое удаление атрибута решит вашу проблему, поскольку Entity Framework вычисляет внешние ключи на основе имени ваших сущностей. Если вы хотите сохранить атрибуты, используйте:

[ForeignKey("Id")]

вместо

[ForeignKey("DeferredDataId")]

Так:

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; }
}

или измените идентификатор DeferredData быть DeferredDataId и не Id

Несколько замечаний об EF:

  1. Свойства с именами Id автоматически являются ключами, поэтому нет необходимости Key атрибут
  2. Когда вы сначала определяете отношения с помощью кода, вам не нужно вручную украшать вещи атрибутами, EF вычисляет их на основе структуры.

Редактировать:

Для отношений один ко многим вам нужен ICollection<T>

public virtual ICollection<MemberDataSet> MemberDataSets { get; set; }

Есть ли UserProfile иметь UserId имущество?

Другие вопросы по тегам