Как я могу установить отношения (0, N: 1,1) с EF Core? - PullRequest
1 голос
/ 22 декабря 2019

Проблема в том, что «Автор может не иметь ни одной или нескольких книг, но книга никогда не пишется двумя или более авторами».

public Author(Document cpf, string name, DateTime birthdate)
        {
            Cpf = cpf;
            Name = name;
            Birthdate = birthdate;
        }

        public Document Cpf { get; private set; }
        public string Name { get; private set; }
        public DateTime Birthdate { get; private set; }
        // EF Relation
        public Book Book { get; private set; }
        public ICollection<Book> Books { get; private set; }

        protected Author() { }

// 0 : N => Author : Books
            builder.HasMany(c => c.Books)
                .WithOne(b => b.Author)
                .HasForeignKey(b => b.AuthorId);
public Book(Guid categoryId, Guid authorId, string title, DateTime releaseDate, BookIdentificator isbn)
        {
            CategoryId = categoryId;
            AuthorId = authorId;
            Title = title;
            ReleaseDate = releaseDate;
            Isbn = isbn;
        }

        public Guid CategoryId { get; private set; }
        public Guid AuthorId { get; private set; }
        public string Title { get; private set; }
        public DateTime ReleaseDate { get; private set; }
        public BookIdentificator Isbn { get; private set; }
        public Category Category { get; private set; }
        public Author Author { get; private set; }
            // 1 : 1 => Books : Author
            builder.HasOne(c => c.Author)
                   .WithOne(b => b.Book)
                   .HasForeignKey(b => b.AuthorId);

Ошибка: невозможнопреобразовать лямбда-выражение в тип 'string', поскольку оно не является делегатом типа BookManager.Catalog.Data

1 Ответ

2 голосов
/ 23 декабря 2019

Это сложная проблема, чтобы помочь вам, потому что вы не опубликовали полный пример ваших классов Author или Book, только фрагменты, и эти фрагменты не являются полными.

Ваша конкретная ошибка обсуждалась:

Невозможно преобразовать лямбда-выражение в тип 'string', поскольку оно не является типом делегата

Это вызвано тем, что компилятор ожидает, что вы будете использовать одну из перегрузок для QueryTypeBuilder.HasOne Method и не найдет соответствия, по умолчанию это перегрузка HasOne(string, string). Вы должны использовать методы расширения, чтобы упростить доступ к текущей конфигурации.

Добавить с помощью операторов:

using System.Linq; 
using System.Data.Entity;

Это только начало ваших проблем, а затем следующее: Author имеет оба следующих свойства:

// EF Relation
public Book Book { get; private set; }
public ICollection<Book> Books { get; private set; }

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

Могу ли я предложить вместо этого вам только свойство Books в Author class:

// EF Relation
public virtual ICollection<Book> Books { get; set; } = new HashSet<Book>();

Тогда ваша беглая запись все еще нуждается в следующей настройке:

Автор

Никаких изменений здесь, это допустимо, используя более длинные имена переменных, чтобы помочьобъясните взаимосвязь.

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

// 0 : N => Author : Books
builder.HasMany(author => a.Books)
       .WithOne(book => book.Author)
       .HasForeignKey(book => book.AuthorId);

Книга

В исходном коде OP неправильно указано, что Book:Authorотношение было 1:1, тогда как на самом деле это Many:1

// N : 1 => Books : Author
builder.HasOne(book => book.Author)
       .WithMany(author => author.Books)
       .HasForeignKey(book => book.AuthorId);

ПРИМЕЧАНИЕ: Хотя вы можете указать каждое отношение в прямой или обратной логике,Каждое отношение необходимо указывать только один раз посредством беглой нотации.

  • Необходимо определить только одну из вышеуказанных конфигураций, обе они описывают одну и ту же ссылку.

Та же конфигурация могла бы быть достигнута с помощью нотации атрибутов в классе Book:

[ForeignKey(nameof(AuthorId))]
public virtual Author Author { get; set; }

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

Кроме того, все свойства коллекции должны автоматически инициализироваться с использованием new HashSet<T>(), чтобы уменьшить объем кода, который необходимо написать для создания объектов во время выполнения, и для поддержки операций с цепочками данных.

...