В настоящее время я получаю следующую ошибку во время dotnet ef migrations add Initial
Невозможно создать «DbContext» типа «».
Исключение «Свойство TestChild.Parent» TestChild.Parent не удалось сопоставить, поскольку поставщик базы данных не поддерживает этот тип.
Рассмотрите возможность преобразования значения свойства в тип, поддерживаемый базой данных, с помощью преобразователя значений.
См. https://aka.ms/efcore-docs-value-converters для получения дополнительной информации.
Альтернативно исключите свойство из модели, используя атрибут «[NotMapped]» или используя «EntityTypeBuilder.Ignore» в «OnModelCreating». был выброшен при попытке создать экземпляр. Информацию о различных шаблонах, поддерживаемых во время разработки, см. https://go.microsoft.com/fwlink/?linkid=851728
Моя минимальная модель выглядит так:
public class RecipeContext : DbContext
{
public DbSet<TestParent> Parents { get; set; }
public RecipeContext(DbContextOptions<RecipeContext> options)
: base(options) { }
}
[PrimaryKey(nameof(Name))]
public class TestParent
{
[Required]
public string Name { get; set; }
public virtual ICollection<TestChild> Children { get; set; }
}
[PrimaryKey(nameof(Parent))]
public class TestChild
{
[Required]
public virtual TestParent Parent { get; set; }
}
В реальном мире TestChild
имеет составной первичный ключ, поэтому он имеет немного больше смысла, чем этот минимальный пример.
Я пробовал это как с поставщиками Sqlite, так и с SQL Server, оба выдают одинаковые ошибки, что заставляет меня полагать, что это не относится к одному поставщику, а вместо этого является либо «ошибкой» в EF Core (v8.0.4), либо чем-то еще. вероятно, какое-то недопонимание того, как навигационные связи/атрибуты внешнего ключа в EF Core работают вместе.
Пока у меня нет элемента навигации/внешнего ключа (Parent) в атрибуте PrimaryKey
для класса TestChild
, это работает. например если я добавлю еще один столбец, например Id
, к TestChild
и буду использовать именно этот столбец в качестве PrimaryKey
для TestChild
, это будет работать.
Однако на самом деле это не соответствует тому ограничению уникальности, которое мне хотелось бы. Для каждого Parent
может быть только один Child
с тем же именем (поэтому в реальном мире мне нужен PrimaryKey(nameof(Parent),nameof(Name)
).
Любое руководство по этому поводу было бы здорово. Возможно, есть документ EF Core, который точно описывает то, что я хочу (и как я делаю это неправильно)?
EF Core работает на основе соглашений по умолчанию и не может понять ваши текущие настройки. По умолчанию EF Core сгенерирует теневой FK для вашей настройки (ParentName
, но обратите внимание, что соглашения могут меняться в зависимости от версии и настройки), и вам необходимо указать его имя для использования в качестве PK (а не имя свойства навигации). Например, для моей минимальной настройки с SQLite работает следующее:
[PrimaryKey("ParentName")]
public class TestChild
{
[Required]
public virtual TestParent Parent { get; set; }
}
Или вы можете явно объявить ключ свойства навигации:
[PrimaryKey(nameof(ParentName))]
public class TestChild
{
public string ParentName { get; set; }
[Required]
[ForeignKey(nameof(ParentName))]
public virtual TestParent Parent { get; set; }
}
Смотрите также:
Более явное использование теневых свойств внешнего ключа действительно помогло. Спасибо. Однако я до сих пор не совсем понимаю, почему это не учтено «конвенциями». Разве свойство навигации уже не подразумевает использование внешнего ключа (и, следовательно, теневых свойств для отношений FK)? Таким образом, использование свойства навигации в атрибуте PrimaryKey() дочернего элемента должно просто «расширяться» до названных свойств тени внешнего ключа.
ПК не может быть свойством навигации. Если у дочернего элемента есть составной ключ ParentName и какого-либо другого столбца, вам необходимо объявить составной ключ, например
[PrimaryKey("ParentName","OtherColumn")]