Объекты отражают модель данных. Представления должны иметь собственное представление модели в зависимости от того, какую информацию вы хотите отобразить.
Например:
[Serializable]
public class BookViewModel
{
public int BookId { get; set; }
public int AuthorId { get; set; }
public string Title { get; set; }
public string Author { get; set; }
}
Затем при загрузке источника данных:
var books = DB.BookAuthors.Select(x => new BookViewModel
{
BookId = x.Book.id,
Author = x.Author.id,
Title = x.Book.title,
Author = x.Author.name
}).ToList();
DGVBookAuthors.DataSource = new BindingSource() { DataSource = books };
Объекты отражают состояние данных. Вы можете проецировать объекты в модели представлений, подходящие для представлений, которые вы хотите отобразить. Когда ваше представление обращается к контроллеру с идентификаторами и данными, вы используете эти идентификаторы для повторной загрузки сущностей и обновления их состояния, если это применимо.
Передача сущностей в представление означает отправку намного большего количества данных клиенту чем требуется, и склонен к таким проблемам, как то, с чем вы столкнулись, плюс другие ошибки сериализации.
Относительно вашей исходной схемы: я подозреваю, что вам не понадобятся отношения «многие ко многим» между книгами и авторами , Хотя у одного автора может быть много книг, у книги должен быть только один автор. Это упростит схему, так что нет таблицы BookAuthor, только AuthorId (idAuthor) в таблице Book. Тогда запрос будет упрощен до:
var books = DB.Books.Select(x => new BookViewModel
{
BookId = x.id,
Author = x.Author.id,
Title = x.title,
Author = x.Author.name
}).ToList();