Id在附加多个具有相同Id的实体时无法移除。

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

Id could not be removed when attached multiple entities with the same Id

问题

Here's the translated content:

我有三个类 GdsReceptionBlackProductEmployee  Customer

public partial class GdsReceptionBlackProduct
{
    public int Id { get; set; }
    public string? CreatedBy { get; set; }
    public virtual Employee? CreatedByNavigation { get; set; }
}

public void Configure(EntityTypeBuilder<GdsReceptionBlackProduct> entity)
{
    entity.HasOne(d => d.CreatedByNavigation).WithMany(p => p.CreatedBy)
    .HasPrincipalKey(p => p.IdEmployee)
    .HasForeignKey(d => d.CreatedBy)
    .HasConstraintName("GDSReceptionBlackProduct_Employee_CreatedBy");
    entity.Navigation(e => e.CreatedByNavigation).AutoInclude();
}

public partial class Employee
{
    public string IdEmployee { get; set; } = null!;
    public int? FkCountry { get; set; }
    public virtual Country Country { get; set; }
    public virtual ICollection<GdsReceptionBlackProduct> CreatedBy { get; } = new List<GdsReceptionBlackProduct>();
}
public void Configure(EntityTypeBuilder<Employee> entity)
{
    entity.HasOne(d => d.Country)
        .WithMany(p => p.Employees)
        .HasForeignKey(d => d.FkCountry)
        .HasConstraintName("FK_Employee_Country");
    entity.Navigation(e => e.Country).AutoInclude();
}
public partial class Customer
{
    public int? Fkcountry { get; set; }
    public virtual Country? Country { get; set; }
    public virtual ICollection<GdsReceptionBlackProduct> GdsReceptionBlackProduct { get; } = new List<GdsReceptionBlackProduct>();
}
public void Configure(EntityTypeBuilder<Customer> entity)
{
    entity.Navigation(e => e.Country).AutoInclude();
}

我正在使用工作单元与存储库模式和依赖注入,所以在 FrmGDSReceptionBlackProduct 中我像这样使用它

public FrmGDSReceptionBlackProduct(GdsReceptionBlackProductService gdsReceptionBlackProductService,
                                       CustomerService customerService)
{
    InitializeComponent();
    this.gdsReceptionBlackProductService = gdsReceptionBlackProductService;
    this.customerService = customerService;
}
当我尝试移除 GdsReceptionBlackProduct

await gdsReceptionBlackProductService.RemoveGdsReceptionBlackProductAsync(Convert.ToInt32(txtID.Text));
public virtual async Task<bool> RemoveAsync(object id)
{
    T? exist = await dbSet.FindAsync(id);
    if (exist == null) throw new ArgumentNullException($"{nameof(RemoveAsync)} entity must not be null");
    dbSet.Remove(exist);
    return true;
}
我收到以下错误消息

> 无法删除 id:无法跟踪实体类型 'Country' 的实例,因为已经有具有键值 '{IdCountry: 1}' 的另一个实例
> 已被跟踪。在附加现有实体时,请确保只有一个具有给定键值的实体实例被附加。

当我注释掉下面的代码行时

entity.Navigation(e => e.CreatedByNavigation).AutoInclude();
然后尝试删除 GdsReceptionBlackProduct 实体,它成功删除了。
我使用 AutoInclude 来在网格视图中显示属性名称。
所有的 CRUD 操作都在同一个窗体中。
如何解决这个问题?
更新
这是我的通用存储库的构造函数

public class GenericRepository<T> : IGenericRepository<T>, IDisposable where T : class

{
    protected SIMContext _context;
    internal DbSet<T> dbSet;
    public GenericRepository(SIMContext context)
    {
        _context = context;
        _context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        dbSet = context.Set<T>();
    }
}
英文:

I have three class GdsReceptionBlackProduct, Employee and Customer

public partial class GdsReceptionBlackProduct
{
public int Id { get; set; }
public string? CreatedBy { get; set; }
public virtual Employee? CreatedByNavigation { get; set; }
}
public void Configure(EntityTypeBuilder&lt;GdsReceptionBlackProduct&gt; entity)
{
entity.HasOne(d =&gt; d.CreatedByNavigation).WithMany(p =&gt; p.CreatedBy)
.HasPrincipalKey(p =&gt; p.IdEmployee)
.HasForeignKey(d =&gt; d.CreatedBy)
.HasConstraintName(&quot;GDSReceptionBlackProduct_Employee_CreatedBy&quot;);
entity.Navigation(e =&gt; e.CreatedByNavigation).AutoInclude();
}  
public partial class Employee
{
public string IdEmployee { get; set; } = null!;
public int? FkCountry { get; set; }
public virtual Country Country { get; set; }
public virtual ICollection&lt;GdsReceptionBlackProduct&gt; CreatedBy { get; } = new List&lt;GdsReceptionBlackProduct&gt;();
}
public void Configure(EntityTypeBuilder&lt;Employee&gt; entity)
{
entity.HasOne(d =&gt; d.Country)
.WithMany(p =&gt; p.Employees)
.HasForeignKey(d =&gt; d.FkCountry)
.HasConstraintName(&quot;FK_Employee_Country&quot;);
entity.Navigation(e =&gt; e.Country).AutoInclude();
}
public partial class Customer
{
public int? Fkcountry { get; set; }
public virtual Country? Country { get; set; }
public virtual ICollection&lt;GdsReceptionBlackProduct&gt; GdsReceptionBlackProduct { get; } = new List&lt;GdsReceptionBlackProduct&gt;();
}
public void Configure(EntityTypeBuilder&lt;Customer&gt; entity)
{
entity.Navigation(e =&gt; e.Country).AutoInclude();
}

I am using unit of work with repository pattern and DI so in FrmGDSReceptionBlackProduct I use it like this

public FrmGDSReceptionBlackProduct(GdsReceptionBlackProductService gdsReceptionBlackProductService,
CustomerService customerService)
{
InitializeComponent();
this.gdsReceptionBlackProductService = gdsReceptionBlackProductService;
this.customerService = customerService;
}

When I try to remove GdsReceptionBlackProduct

await gdsReceptionBlackProductService.RemoveGdsReceptionBlackProductAsync(Convert.ToInt32(txtID.Text));
public virtual async Task&lt;bool&gt; RemoveAsync(object id)
{
T? exist = await dbSet.FindAsync(id);
if (exist == null) throw new ArgumentNullException($&quot;{nameof(RemoveAsync)} entity must not be null&quot;);
dbSet.Remove(exist);
return true;
}

I get this error message

> id could not be removed: The instance of entity type 'Country' cannot
> be tracked because another instance with the key value '{IdCountry:
> 1}'
> is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

when I comment the below line of code

entity. Navigation(e =&gt; e.CreatedByNavigation).AutoInclude();

and I trying to remove the GdsReceptionBlackProduct entity it removed successfully.
I am using AutoInclude to show the properties names in grid view.
All CRUD operations are in the same form.
How can I fix this issue?
Update
this is the constructor of my generic repository

public class GenericRepository&lt;T&gt; : IGenericRepository&lt;T&gt;, IDisposable where T : class
{
protected SIMContext _context;
internal DbSet&lt;T&gt; dbSet;
public GenericRepository(SIMContext context)
{
_context = context;
_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
dbSet = context. Set&lt;T&gt;();
}

答案1

得分: 0

问题在于Entity Framework Core同时为相同的实体实例打开了两个数据库连接,并且同时尝试跟踪这两个连接。当你使用.AutoInclude加载国家实体时,第一个跟踪开始,当你使用RemoveAsync方法时,第二个跟踪开始。你的解决方案是在其中一个地方不跟踪Country实体,所以你应该使用.AsNoTracking

public virtual async Task<bool> RemoveAsync(object id)
{
    PropertyInfo? idProperty = typeof(T).GetProperty("Id");
    if (idProperty == null)
        throw new ArgumentException($"Entity type {typeof(T).Name} does not have an 'Id' property.");

    T? exist = await dbSet.Set<T>().AsNoTracking().FirstOrDefaultAsync(e => idProperty.GetValue(e).Equals(id));
    if (exist == null) throw new ArgumentNullException($"{nameof(RemoveAsync)} entity must not be null");
    dbSet.Remove(exist);

    return true;
}
英文:

The problem is that Entity Framework Core is opening two connections to the database for the same entity instance at the same time and also trying to track both concurrently. When you .AutoInclude the country entity, the 1st tracking begins and when you use the RemoveAsync method, the 2nd tracking begins. Your solution would be to not track the Country entity at one of them, so you should use .AsNoTracking :

public virtual async Task&lt;bool&gt; RemoveAsync(object id)
{
PropertyInfo? idProperty = typeof(T).GetProperty(&quot;Id&quot;);
if (idProperty == null)
throw new ArgumentException($&quot;Entity type {typeof(T).Name} does not have an &#39;Id&#39; property.&quot;);
T? exist = await dbSet.Set&lt;T&gt;().AsNoTracking().FirstOrDefaultAsync(e =&gt; idProperty.GetValue(e).Equals(id));
if (exist == null) throw new ArgumentNullException($&quot;{nameof(RemoveAsync)} entity must not be null&quot;);
dbSet.Remove(exist);
return true;
}

答案2

得分: 0

感谢Richard Deeming,我得到了答案

英文:

Thanks to Richard Deeming I get the answer

huangapple
  • 本文由 发表于 2023年6月8日 16:54:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76430179.html
匿名

发表评论

匿名网友

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

确定