简体   繁体   English

实体框架避免多对多关系中的重复

[英]Entity Framework avoid duplications in many to many relations

I've been stuck a little with the EF 6 database-first approach.我对 EF 6 数据库优先的方法有些困惑。

I have 3 tables in SQL Server:我在 SQL 服务器中有 3 个表:

  • Members成员
  • Teams团队
  • JT_Teams_Members (junction table) JT_Teams_Members(联结表)

I would like to insert to data to this relations.我想将数据插入到这种关系中。

From the code, I get a list of teams that I iterated从代码中,我得到了我迭代的团队列表

Inserting:插入:

foreach (var team in teams.Teams)
{
    var teamEntity = new Contexts.Team
            {
                TeamName = team.Name,
                ....
            };

    foreach (var member in team.Members)
    {
        teamEntity.Members.Add(
                new Contexts.Member()
                {
                    MemberName = member.Name,
                    EmailAddress = member.Email,  
                ...
                });
    }

    DbUtility.Context.Teams.Add(teamEntity);
}

My problem is I found a lot of duplication in the members table, which is not so good.我的问题是我在 members 表中发现了很多重复,这不太好。

How can I manage the inserting to avoid the duplication and redirecting the ids to the properly place?如何管理插入以避免重复并将 ID 重定向到正确的位置?

When dealing with associations, you will want to use the same reference for related entities rather than new-ing up a new reference for each related entity.在处理关联时,您将希望对相关实体使用相同的引用,而不是为每个相关实体新建一个引用。

If I'm inserting a number of teams that contain members and some of those members may be new and shared across teams, while others could be existing members already in the database:如果我要插入多个包含成员的团队,其中一些成员可能是新成员并在团队之间共享,而其他成员可能是数据库中已有的成员:

  1. For all associated entities, always pass PKs in your view models.对于所有关联实体,始终在您的视图模型中传递 PK。 For members, if you can select from existing members, even if you only display a name and e-Mail address, pass the Member ID in your view model for later lookups.对于会员,如果您可以从现有会员中获取 select,即使您只显示姓名和电子邮件地址,也请在您的视图 model 中传递会员 ID 以供以后查找。

From there we can start to look at something like below:从那里我们可以开始看下面的东西:

var memberIds = teams.Teams
    .SelectMany(t => t.Members)
    .Select(m => m.MemberId)
    .Where(m => m.MemberId != 0)
    .ToList();

var existingMembers = Context.Members
    .Where(m => memberIds.Contains(m.MemberId))
    .ToList();


foreach (var team in teams.Teams)
{
    var teamEntity = new Contexts.Team
    {
        TeamName = team.Name,
        ....
    };

    foreach (var member in team.Members)
    {   //We assume that all e-mail addresses are unique.
        var existingMember = existingMembers.SingleOrDefault(m => m.Email == member.Email);
        if (existingMember == null)
        {
            existingMember = new Member()
            {
                MemberName = member.Name,
                EmailAddress = member.Email,  
            ...
            });
            existingMembers.Add(existingMember); // For future reference.
        }
        teamEntity.Members.Add(existingMember);
    }

    DbUtility.Context.Teams.Add(teamEntity);
}

The first step is to look for any existing members for the teams.第一步是为团队寻找任何现有成员。 If you know that there will be no existing members then you can skip that load, and just use an initially empty collection.如果您知道将存在现有成员,那么您可以跳过该加载,而只需使用最初为空的集合。 As we go through our teams we first check the existing collection for a member matching the e-mail address.当我们通过我们的团队 go 时,我们首先检查现有集合中是否有与电子邮件地址匹配的成员。 If we find one, we use it, otherwise we create a new member and add it to the collection.如果我们找到一个,我们使用它,否则我们创建一个新成员并将其添加到集合中。 That way when another team with the same member is added, it is found in the collection and the same reference will be used.这样,当添加具有相同成员的另一个团队时,它会在集合中找到并且将使用相同的引用。

When EF inserts data, it respects references, not necessarily IDs/constraints to associate entities to the same reference rather than creating duplicates.当 EF 插入数据时,它尊重引用,不一定是 ID/约束将实体关联到相同的引用,而不是创建重复项。 If you have 2 entities that reference the same member (joe.smith@gmail.com) then you want to ensure that both entities reference the same member entity for joe.smith, not 2 different entities with the same e-mail address.如果您有 2 个实体引用同一个成员 (joe.smith@gmail.com),那么您要确保两个实体引用 joe.smith 的同一个成员实体,而不是 2 个具有相同电子邮件地址的不同实体。 When dealing with bulk operations (inserting many teams) you will want to keep a local cache or read from the DbContext to leverage its cache.在处理批量操作(插入许多团队)时,您将希望保留本地缓存或从 DbContext 读取以利用其缓存。 For single operations you should always go to the DbContext to retrieve an existing entity if available before attempting to create a new reference.对于单个操作,您应该始终 go 到 DbContext 以在尝试创建新引用之前检索现有实体(如果可用)。 (To avoid duplicate data or constraint violations/duplicate key exceptions.) (避免重复数据或违反约束/重复键异常。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM