从列表中提取属性并插入到另一个表中

问题描述 投票:0回答:1

我有一个名为

Personel
的表,每个
Personel
包含一个
List<Eblagh>
。其中有一个名为
Vahed
的属性。

我想找到人员(eblaghs)中可用的所有

Vahed
,并将它们插入另一个名为
School
的表中,在该表中,我们必须有一列来保存所有相关的
Personel

这些是我的课程:

public class Personel
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    ...

    public int AreaId { get; set; }
    public Area Area { get; set; }

    public List<PersonelSchool> PersonelSchools { get; set; } = new();
    public List<Eblagh> Eblaghs { get; set; } = new();
}

public class Eblagh
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Vahed { get; set; }
    ...
    public int PersonelId { get; set; }
    public Personel Personel { get; set; }
}

public class School
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public List<PersonelSchool> PersonelSchools { get; set; } = new();
}

public class PersonelSchool
{
    public int PersonelId { get; set; }
    public Personel Personel { get; set; }

    public int SchoolId { get; set; }
    public School School { get; set; }
}

我使用了以下代码:

var personelsWithEblagh = 
    await db.Personels
            .Where(x => x.AreaId == Area.Id)
            .Include(p => p.Eblaghs)
            .ToListAsync();

foreach (var personel in personelsWithEblagh)
{
    foreach (var eblagh in personel.Eblaghs)
    {
        var schoolName = eblagh.Vahed;

        var existingSchool = await db.Schools.FirstOrDefaultAsync(s => s.Name == schoolName);

        if (existingSchool == null)
        {
            var newSchool = new School { Name = schoolName };
            await db.Schools.AddAsync(newSchool);
            await db.SaveChangesAsync();
            existingSchool = newSchool;
        }

        personel.PersonelSchools.Add(new PersonelSchool
        {
            PersonelId = personel.Id,
            SchoolId = existingSchool.Id
        });
    }
}

await db.SaveChangesAsync();

这是我的

DbContext

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PersonelSchool>()
        .HasKey(ps => new { ps.PersonelId, ps.SchoolId });

    modelBuilder.Entity<PersonelSchool>()
        .HasOne(ps => ps.Personel)
        .WithMany(p => p.PersonelSchools)
        .HasForeignKey(ps => ps.PersonelId)
        .OnDelete(DeleteBehavior.Cascade);

    modelBuilder.Entity<PersonelSchool>()
        .HasOne(ps => ps.School)
        .WithMany(s => s.PersonelSchools)
        .HasForeignKey(ps => ps.SchoolId)
        .OnDelete(DeleteBehavior.Cascade);
}

问题是操作抛出错误

System.InvalidOperationException:实体类型的实例 无法跟踪“PersonelSchool”,因为另一个实例具有 {'PersonelId', 'SchoolId'} 的相同键值已被使用 被跟踪。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用 'DbContextOptionsBuilder.EnableSensitiveDataLogging' 查看 关键值冲突。

在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap

1.ThrowIdentityConflict(InternalEntityEntry entry)     at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap
1.Add(TKey 键,InternalEntityEntry 条目,布尔值 updateDuplicate)
在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap
1.Add(TKey key, InternalEntityEntry entry)     at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NullableKeyIdentityMap
1.Add(InternalEntityEntry 条目)

如果我添加

.AsNoTracking()
,学校名称将被添加到表中,但是,我再次收到错误并且
PersonelSchool
表为空

c# .net entity-framework entity-framework-core ef-code-first
1个回答
0
投票

您可以在插入关联项目之前检查预先存在的项目,如下面的代码所示 - 即在 PersonnelsWithEBlagh 中包含 PersonnelSchools,并在添加之前检查其内容。您可能最好确定为什么它会插入您不希望插入的项目。

var personelsWithEblagh = 
   await db.Personels
        .Where(x => x.AreaId == Area.Id)
        .Include(p => p.Eblaghs)
        .Include(p => p.PersonelSchools   // Include the existing personnelschools
        .ToListAsync();

foreach (var personel in personelsWithEblagh)
{
foreach (var eblagh in personel.Eblaghs)
{
    var schoolName = eblagh.Vahed;

    var existingSchool = await db.Schools.FirstOrDefaultAsync(s => s.Name == schoolName);

    if (existingSchool == null)
    {
        var newSchool = new School { Name = schoolName };
        await db.Schools.AddAsync(newSchool);
        await db.SaveChangesAsync();
        existingSchool = newSchool;
    }

    if(!personel.PersonelSchools.Any(x=>x.SchoolId == existingSchool.Id)) // Check for existing item in the association table
    {
       personel.PersonelSchools.Add(new PersonelSchool
       {
           PersonelId = personel.Id,
           SchoolId = existingSchool.Id
       });
    }
}
}

await db.SaveChangesAsync();
© www.soinside.com 2019 - 2024. All rights reserved.