访问透明的EF管理的关联实体(多对多关系),无需类/DbSet。

huangapple go评论125阅读模式
英文:

Access transparent EF managed join entity (many to many relationship) without class/DbSet

问题

我采用了代码优先的方法(EF Core 7.0)。我没有明确定义使用类的连接实体。现在我想访问连接实体并删除或添加一些行,但我无法做到。

模型精简到了基本要素。实际上,A 和 B 中有许多列。

public class A
{
    public int Id { get; set; }
    public List<B> Bs { get; } = new();
}

public class B
{
    public int Id { get; set; }
    public List<A> As { get; } = new();
}

假设在表中有以下数据:

表 A:
1
2
3
4
5
6

表 B:
1
2
3

EF 管理的连接实体表 AB:
1 1
1 2
1 3

我有两个列表。要添加或删除连接实体中的 ID。

A ID: 1

要添加的列表 ToAdd: 4, 5
要删除的列表 ToRemove: 2, 3

最终表格应如下所示:

EF 管理的连接实体表 AB:
1 1
1 4
1 5

如何高效实现所需结果?我想直接访问由 EF Core 管理的实体,但这不可能,因为没有类存在,也没有 DbSet。

任何帮助将不胜感激。非常感谢!

英文:

I have taken the code first approach (EF Core 7.0). I have not explicitly defined the join entity using a class. Now I want to access the join entity and delete or add some rows there, which I am not able to do.

Model reduced to the essentials. In reality, there are many columns in A and B.

public class A
{
    public int Id { get; set; }
    public List&lt;B&gt; Bs { get; } = new();
}

public class B
{
    public int Id { get; set; }
    public List&lt;A&gt; As { get; } = new();
}

Let's say in the table there are the following data:

Table A:
1
2
3
4
5
6


Table B:
1
2
3

EF managed join entity Table AB:
1 1
1 2
1 3

I have two lists. Add and Remove. The IDs should be added or removed from the joined entity.

A ID: 1

List ToAdd: 4, 5
List ToRemove: 2,3

At the end the table should look like this

EF managed join entity Table AB:
    1 1
    1 4
    1 5

How do I achieve the desired result very efficiently? I would like to access directly the entity managed by EF Core, but this is not possible because no class exists and no DbSet.

Any help would be appreciated. Thanks a lot!

答案1

得分: 1

您实际上可以自己定义连接实体并将导航属性移到该实体中。它将在数据库上产生与您已经在做的相同结果,但您还将拥有连接实体,可以在LINQ中使用。以下是您可以这样做的方法:

public class A
{
    public int Id { get; set; }
}

public class B
{
    public int Id { get; set; }
}

public class AandB
{
    public List<A> As { get; } = new();
    public List<B> Bs { get; } = new();
}
英文:

You actually can define the join entity yourself and move the navigational properties into this entity. It will yield the same result on the database as what you are already doing, but you will also have the join entity which you can use with LINQ. Here is how you could do this:

public class A
{
    public int Id { get; set; }
}

public class B
{
    public int Id { get; set; }
}

public class AandB
{
    public List&lt;A&gt; As { get; } = new();
    public List&lt;B&gt; Bs { get; } = new();
}

答案2

得分: 0

我不确定我理解你的示例。如果你有一组要添加和删除的BIds,你可以直接使用A的导航属性来这样做。通常让新手开发者感到困惑的是,为了这样做,你需要确保首先预加载Bs集合。例如,如果我有两个集合:BsToAdd和BsToRemove:

A a = _context.As
    .Include(a => a.Bs) // <- 确保Bs已加载并可用。
    .Single(a => a.Id == aId);

foreach(var b in BsToRemove)
    a.Bs.Remove(b);

foreach(var b in BsToAdd)
    a.Bs.Add(b);

EF将自动管理关联表的更新。现在这只是一个非常基本的示例,你可能希望在删除之前检查集合以确保所需的B存在,或者在添加之前检查B是否存在,并且如果涉及到B实体,我们需要确保任何引用都由这个DbContext实例跟踪。

EF可以完全在后台管理关联表,但在需要更多于关联关系中的A_Id和B_Id的情况下,比如有一个"IsActive"或其他与关联关系特定的详细信息,你需要定义和映射一个AB实体。这会看起来更像:

public class A
{
    public int Id { get; set; }
    public List<AB> ABs { get; } = new();
}

public class B
{
    public int Id { get; set; }
    public List<AB> ABs { get; } = new();
}
    
public class AB
{   
    public int AId { get; set; }  // 这些ID需要映射为复合主键。
    public int BId { get; set; }

    public bool IsActive { get; set; } = true; // 例如

    public A A {get; set;}
    public B B {get; set;}
}

这种方法的优点是你可以跟踪A和B之间的关系信息,但不便之处在于你总是需要通过AB实体来从A获取相关的Bs,反之亦然。所以,例如,要将B添加到A,你不能只是a.Bs.Add(b),它必须类似于a.ABs.Add(new AB { A = a, B = b })。此外,当急切加载Bs时:

A a = _context.As
    .Include(a => a.ABs)
        .ThenInclude(ab => B)
    .Single(a => a.Id == aId);

定义关联实体更加灵活,但也更加繁琐。

英文:

I'm not sure I follow your example. If you have sets of BIds that you want to add and remove respectively, you can do so with A's navigation property to Bs directly. The catch that often trips up developers new to EF is to do so you need to ensure you first eager load the Bs collection. For example if I have two collections: BsToAdd and BsToRemove:

A a = _context.As
    .Include(a =&gt; a.Bs) // &lt;- Make sure the Bs are loaded and available.
    .Single(a =&gt; a.Id == aId);

foreach(var b in BsToRemove)
    a.Bs.Remove(b);

foreach(var b in BsToAdd)
    a.Bs.Add(b);

EF will manage the linking table updates automatically. Now this is a very basic example, you might want to check the collection to ensure the desired B exists before removing, or doesn't exist before adding, and if dealing with B entities we would need to ensure that any references are tracked by this DbContext instance.

EF can manage linking tables entirely behind the scenes, but in cases where you want more than just an A_Id and B_Id in the associated relationship, such as having an "IsActive" or other details specific to the relationship, you would need to define and map an AB entity. This would look more like:

public class A
{
    public int Id { get; set; }
    public List&lt;AB&gt; ABs { get; } = new();
}

public class B
{
    public int Id { get; set; }
    public List&lt;AB&gt; ABs { get; } = new();
}
    
public class AB
{   
    public int AId { get; set; }  // These IDs need to be mapped as a composite PK.
    public int BId { get; set; }

    public bool IsActive { get; set; } = true; // for example

    public A A {get; set;}
    public B B {get; set;}
}

The advantage of this approach is that you can track information about the relationship between A & B, but the trade-off is that you always need to go through the AB entity to get at the related Bs from A and vice versa. So for instance to add a B to an A you cannot just go a.Bs.Add(b), it needs to be something like a.ABs.Add(new AB { A = a, B = b }) Also when eager loading Bs:

A a = _context.As
    .Include(a =&gt; a.ABs)
        .ThenInclude(ab =&gt; B)
    .Single(a =&gt; a.Id == aId);

Defining linking entities is more flexible, but also a bit more hassle to work with.

huangapple
  • 本文由 发表于 2023年7月27日 20:22:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76779696.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定