我如何与 EF Core 建立关系 (0,N:1,1)?
How can i make a relationship (0,N:1,1) with EF Core?
问题是"An author may have none or many books, but a book is never written by two or more authors."
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);
错误:无法将 lambda 表达式转换为类型 'string',因为它不是委托类型 BookManager.Catalog.Data
看不到您的代码有任何问题。也许您只缺少 using
语句? Cannot convert lambda expression to type 'string' because it is not a delegate type
这是一个很难帮助您解决的问题,因为您没有发布 Author
或 Book
class 的完整示例,只有片段,而这些片段并不完整足够。
您的具体错误已被讨论:
Cannot convert lambda expression to type 'string' because it is not a delegate type
这是因为编译器希望您使用 QueryTypeBuilder.HasOne Method 的重载之一,但找不到匹配项,它默认为 HasOne(string, string)
的重载。您应该使用扩展方法来简化对流畅配置的访问。
添加 using 语句:
using System.Linq;
using System.Data.Entity;
这只是您问题的开始,下一个问题是 Author
具有以下两个属性:
// EF Relation
public Book Book { get; private set; }
public ICollection<Book> Books { get; private set; }
在这里你是说每个作者都有一本特定的书 AND 一组书。
在不了解应用程序的其余部分的情况下,这可能是有效的,也许单本书参考是作者的传记?或者他们的第一本书?无论哪种方式,如果您希望存在这样的关系,您将需要使用流畅的符号来具体描述用于这两种关系的端点。
我建议您只需要 Author
class:
上的 Books
属性
// EF Relation
public virtual ICollection<Book> Books { get; set; } = new HashSet<Book>();
那么您的流利记法还需要进行以下调整:
作者
这里没有变化,这个是有效的,使用更长的变量名来帮助解释关系。
You do not have to reduce variable names in linq statements to a single character, but if you do, please use the first character of the conceptual variable name or the type, to make it easier to read and review the expectations of the code.
// 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);
NOTE: Although you can specify each relationship in a forward or reverse logic, it is only necessary to specify each relationship once via fluent notation.
- Only one of the above configurations needs to be defined, they are both describing the same link.
The same configuration could have been achieved with attribute notation on the Book
class:
[ForeignKey(nameof(AuthorId))]
public virtual Author Author { get; set; }
关于我的代码风格的最后一点,我建议将所有导航属性声明为虚拟的,以促进延迟加载和更改跟踪优化。
此外,所有集合属性都应使用 new HashSet<T>()
自动初始化,以减少在运行时创建对象所需编写的代码,并支持链式数据操作。
问题是"An author may have none or many books, but a book is never written by two or more authors."
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);
错误:无法将 lambda 表达式转换为类型 'string',因为它不是委托类型 BookManager.Catalog.Data
看不到您的代码有任何问题。也许您只缺少 using
语句? Cannot convert lambda expression to type 'string' because it is not a delegate type
这是一个很难帮助您解决的问题,因为您没有发布 Author
或 Book
class 的完整示例,只有片段,而这些片段并不完整足够。
您的具体错误已被讨论:
Cannot convert lambda expression to type 'string' because it is not a delegate type
这是因为编译器希望您使用 QueryTypeBuilder.HasOne Method 的重载之一,但找不到匹配项,它默认为 HasOne(string, string)
的重载。您应该使用扩展方法来简化对流畅配置的访问。
添加 using 语句:
using System.Linq;
using System.Data.Entity;
这只是您问题的开始,下一个问题是 Author
具有以下两个属性:
// EF Relation
public Book Book { get; private set; }
public ICollection<Book> Books { get; private set; }
在这里你是说每个作者都有一本特定的书 AND 一组书。 在不了解应用程序的其余部分的情况下,这可能是有效的,也许单本书参考是作者的传记?或者他们的第一本书?无论哪种方式,如果您希望存在这样的关系,您将需要使用流畅的符号来具体描述用于这两种关系的端点。
我建议您只需要 Author
class:
Books
属性
// EF Relation
public virtual ICollection<Book> Books { get; set; } = new HashSet<Book>();
那么您的流利记法还需要进行以下调整:
作者
这里没有变化,这个是有效的,使用更长的变量名来帮助解释关系。
You do not have to reduce variable names in linq statements to a single character, but if you do, please use the first character of the conceptual variable name or the type, to make it easier to read and review the expectations of the code.
// 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);
NOTE: Although you can specify each relationship in a forward or reverse logic, it is only necessary to specify each relationship once via fluent notation.
- Only one of the above configurations needs to be defined, they are both describing the same link.
The same configuration could have been achieved with attribute notation on the
Book
class:[ForeignKey(nameof(AuthorId))] public virtual Author Author { get; set; }
关于我的代码风格的最后一点,我建议将所有导航属性声明为虚拟的,以促进延迟加载和更改跟踪优化。
此外,所有集合属性都应使用 new HashSet<T>()
自动初始化,以减少在运行时创建对象所需编写的代码,并支持链式数据操作。