Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Fluent API,多对多实体框架核心_C#_Entity Framework_Code First_Ef Fluent Api - Fatal编程技术网

C# Fluent API,多对多实体框架核心

C# Fluent API,多对多实体框架核心,c#,entity-framework,code-first,ef-fluent-api,C#,Entity Framework,Code First,Ef Fluent Api,我在stackoverflow中搜索了一个合适的解决方案,使用EF Core、Code first和Fluent API生成一个多对多关系 一个简单的场景是: public class Person { public Person() { Clubs = new HashSet<Club>(); } public int PersonId { get; set; } public virtual ICollection<Club&

我在stackoverflow中搜索了一个合适的解决方案,使用EF Core、Code first和Fluent API生成一个多对多关系

一个简单的场景是:

public class Person
{
    public Person() {
        Clubs = new HashSet<Club>();
    }
    public int PersonId { get; set; }
    public virtual ICollection<Club> Clubs { get; set; }
}

public class Club
{
    public Club() {
        Persons = new HashSet<Person>();
    }
    public int ClubId { get; set; }
    public virtual ICollection<Person> Persons { get; set; }
}
公共类人物
{
公众人士(){
lubs=新HashSet();
}
公共int PersonId{get;set;}
公共虚拟ICollection俱乐部{get;set;}
}
公共班级俱乐部
{
公共俱乐部(){
Persons=新HashSet();
}
public int ClubId{get;set;}
公共虚拟ICollection人员{get;set;}
}
请纠正我,如果我错了,但我真的找不到一个问题,其中包含一个详细的解释,如何使用所描述的工具做到这一点。
有人能解释一下这是怎么做到的吗?

EF Core 5.0 RC1+

从EF Core 5.0 RC1开始,可以在没有显式联接表的情况下执行此操作。EF Core能够为问题中显示的多对多关系配置映射,而无需创建
PersonClub
类型

有关更多信息,请参见官方文档中的

以前的版本

如果不为联接使用显式类,这在EF Core中是不可能的。有关如何执行此操作的示例,请参见

Github上有一个开放的请求,要求能够在不需要显式类的情况下实现这一点,但它尚未完成

使用您的场景,我链接的示例将推荐以下实体类:

public class Person
{
    public int PersonId { get; set; }
    public virtual ICollection<PersonClub> PersonClubs { get; set; }
}

public class Club
{
    public int ClubId { get; set; }
    public virtual ICollection<PersonClub> PersonClubs { get; set; }
}

public class PersonClub
{
    public int PersonId { get; set; }
    public Person Person { get; set; }
    public int ClubId { get; set; }
    public Club Club { get; set; }
}
如果你觉得有必要,一定要转到我链接的公开问题,表达你的沮丧

编辑:公开问题建议使用一个简单的
Select
来浏览这个有点麻烦的层次结构。要从
个人ID
俱乐部的集合,您可以使用。e、 g:


我不能保证这是否是一个真正的“最佳实践”,但它肯定会起作用,而且我认为公平地说,它并不太丑陋。

因此,每个
人都有零个或多个
俱乐部,每个
俱乐部都有零个或多个
人。正如你所说的,这是一个正确的多对多关系

您可能知道,关系数据库需要一个额外的表来实现这种多对多关系。实体框架的好处在于,它能够识别这种关系并为您创建这个额外的表

乍一看,这个额外的表不是
DbContext
中的
dbSet
似乎是一个问题:“如果没有
dbSet
,如何与这个额外的表执行连接?”

幸运的是,您不需要在查询中提到这个额外的表。

如果你需要一个问题,比如“给我所有的‘俱乐部’…从每个‘人’那里……”,不要考虑加入。而是使用ICollections

让所有“John Doe”人员参加所有乡村俱乐部:

var result = myDbContext.Persons
    .Where(person => person.Name == "John Doe")
    .Select(person => new
    {
        PersonId = person.Id,
        PersonName = person.Name,
        AttendedCountryClubs = person.Clubs
            .Where(club => club.Type = ClubType.CountryClub),
    };
实体框架将认识到需要使用额外的多对多表进行连接,并将执行此连接,而无需提及此额外表

反过来说:让所有的乡村俱乐部都有他们的“约翰·多伊”成员:

我曾经经历过,一旦我开始在生成的集合中思考我想要的,而不是获得这些集合所需的联接,我发现我几乎不使用联接。一对多关系和多对多关系都是如此。实体框架将在内部使用正确的联接。

正确的“设置”是:

public class Person
{
    public int PersonId { get; set; }
    public virtual ICollection<PersonClub> PersonClubs { get; set; }
}

public class Club
{
    public int ClubId { get; set; }
    public virtual ICollection<PersonClub> PersonClubs { get; set; }
}

public class PersonClub
{
    public int PersonId { get; set; }
    public Person Person { get; set; }
    public int ClubId { get; set; }
    public Club Club { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PersonClub>()
        .HasKey(pc => new { pc.PersonId, pc.ClubId });
}
公共类人物
{
公共int PersonId{get;set;}
公共虚拟ICollection PersonClubs{get;set;}
}
公共班级俱乐部
{
public int ClubId{get;set;}
公共虚拟ICollection PersonClubs{get;set;}
}
公共级个人俱乐部
{
公共int PersonId{get;set;}
公众人物{get;set;}
public int ClubId{get;set;}
公共俱乐部{get;set;}
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity()
.HasKey(pc=>new{pc.PersonId,pc.ClubId});
}
因此,这个用于配置“粘合表”的块是不必要的,如@Kirk示例中所示:

modelBuilder.Entity<PersonClub>()
    .HasOne(pc => pc.Person)
    .WithMany(p => p.PersonClubs)
    .HasForeignKey(pc => pc.PersonId);

modelBuilder.Entity<PersonClub>()
    .HasOne(pc => pc.Club)
    .WithMany(c => c.PersonClubs)
    .HasForeignKey(pc => pc.ClubId);
modelBuilder.Entity()
.HasOne(pc=>pc.Person)
.WithMany(p=>p.PersonClubs)
.HasForeignKey(pc=>pc.PersonId);
modelBuilder.Entity()
.HasOne(pc=>pc.Club)
.有许多(c=>c.个人俱乐部)
.HasForeignKey(pc=>pc.ClubId);

如果在链接实体中使用[ForeignKey]属性,则不需要任何代码。即便如此:可悲的是,它不像早期版本那样工作。在为Core开发的4年中,他们无法使其与以前的版本相匹配。不必要并不意味着不正确。在配置中明确并没有什么坏处,实际上很多时候有助于避免由隐式EF核心约定引起的意外。有人要求提供一种摆脱所有约定的方法,并要求对所有内容进行显式配置。
Person
Club
的流畅映射如何?如何根据PersonClub内的人员和信息正确检索所有俱乐部。像Person.Clubs?迁移到5.0很简单,工作也很完美。您能提供ClubsController方法作为示例吗?我需要类似于[EnableQuery]public IActionResult Get(){返回Ok(_dbContext.Clubs.Include(x=>x.PersonClubs)。然后包含(x=>x.PersonClubs));}的内容,但这不起作用
var result = myDbContext.Clubs
    .Where(club => club.Type = ClubType.CountryClub)
    .Select(club => new
    {
         ClubId = club.Id,
         ClubName = club.Name,
         AnonymousMembers = club.Persons
             .Where(person => person.Name == "John Doe"),
    }
public class Person
{
    public int PersonId { get; set; }
    public virtual ICollection<PersonClub> PersonClubs { get; set; }
}

public class Club
{
    public int ClubId { get; set; }
    public virtual ICollection<PersonClub> PersonClubs { get; set; }
}

public class PersonClub
{
    public int PersonId { get; set; }
    public Person Person { get; set; }
    public int ClubId { get; set; }
    public Club Club { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PersonClub>()
        .HasKey(pc => new { pc.PersonId, pc.ClubId });
}
modelBuilder.Entity<PersonClub>()
    .HasOne(pc => pc.Person)
    .WithMany(p => p.PersonClubs)
    .HasForeignKey(pc => pc.PersonId);

modelBuilder.Entity<PersonClub>()
    .HasOne(pc => pc.Club)
    .WithMany(c => c.PersonClubs)
    .HasForeignKey(pc => pc.ClubId);