I have the following classes:
public class Equipment
{
public const string TableName = "ew_equipamento";
public int EquipmentId { get; set; }
public int IdLote { get; private set; }
public LTE_dp_to_dp _Lote { get; set; }
}
//Mapp:
public void Configure(EntityTypeBuilder<Equipment> builder)
{
builder.ToTable(Equipamento.TableName);
builder.HasKey(x => x.EquipmentId);
builder.HasOne(x => x._Lote)
.WithOne()
.HasForeignKey<Equipment>(x => x.LotId);
builder.HasOne(x => x._Model)
.WithOne()
.HasForeignKey<Equipment>(x=> x.IdEquipmentModel);
}
// -------
public class LTE_dp_to_dp
{
public const string TableName = "ew_lte_cd_to_ft";
public int IdLote { get; set; }
public List<LTE_dp_to_dp_Equipamento> _LoteEquipamentos { get; set; }
}
//Mapp:
public void Configure(EntityTypeBuilder<LTE_dp_to_dp> builder)
{
builder.ToTable(LTE_dp_to_dp.TableName);
builder.HasKey(x => x.IdLote);
builder.HasMany(x => x._LoteEquipamentos)
.WithOne(x=> x._Lote)
.HasForeignKey(x => x.IdLote)
.OnDelete(DeleteBehavior.Restrict);
}
// -----
public class LTE_dp_to_dp_Equipamento
{
public const string TableName = "ew_lte_cd_to_ft_equipamento";
public int EquipmentLoteId { get; set; }
public int EquipmentId { get; set; }
public Equipment _Equipment { get; set; }
public int IdLote { get; set; }
public LTE_dp_to_dp _Lote { get; set; }
}
//Mapp:
public void Configure(EntityTypeBuilder<LTE_dp_to_dp_Equipamento> builder)
{
builder.ToTable(LTE_dp_to_dp_Equipamento.TableName);
builder.HasKey(x => x.IdLoteEquipamento);
builder.HasOne(x => x._Equipment)
.WithOne()
.HasForeignKey<LTE_dp_to_dp_Equipamento>(x => x.IdEquipamento);
builder.HasOne(x => x._Lote)
.WithMany(x=> x._LoteEquipamentos)
.HasForeignKey(x => x.IdLote);
}
And I use the repositories pattern to search:
public async Task<LTE_dp_to_dp> GetAsync(int idLote)
=> await Query(x => x.IdLote == idLote)
.Include(x => x._LoteEquipamentos.OrderBy(o => o.Caixa).ThenBy(o => o.IdLoteEquipamento))
.ThenInclude(x => x._Equipment).ThenInclude(x => x._Model)
.Include(x => x._LoteEquipamentos)
.FirstOrDefaultAsync();
to update:
public void Update(TEntity model)
{
DbSet.Attach(model);
var entry = _context.Entry(model);
entry.State = EntityState.Modified;
}
to save changes:
public async Task<bool> CommitAsync()
{
int _changesNumber = await _context.SaveChangesAsync();
return _changesNumber > 0;
}
I search using GetAsync
, cycle through the items, and change the equipment.
LTE_dp_to_dp lot = await _lteDpToDpRepository.GetAsync(idLote);`
Then, I go through the items:
foreach(var i in lot._LoteEquipamentos)
{
i._Equipment.LotId = other....
_equipamentoRepository.Update(i._Equipamento);
}
await _uow.CommitAsync();
but I get the following error:
Unable to save changes because a circular dependency was detected in the data to be saved: 'Equipamento { 'IdEquipamento': 1571455 } [Modified] <-
Index { 'ModelEquipmentId': 25 } Equipment { 'EquipmentId': 1571456 } [Modified] <-
Index { 'ModelEquipmentId': 25 } Equipment { 'EquipmentId': 1571455 } [Modified]'.
I have already tried the following scenario:
foreach(var i in lot._LoteEquipamentos)
{
i._Equipment.LotId = other....
i._Equipment._Model = null;
_equipamentoRepository.Update(i._Equipamento);
}
but I keep getting the same error...
EF Core 7..8
I expected update value from entity Equipamento
, but I can't because of this error...
The issue here is with the one-to-one relationship you define between the Equipment
and the LTE_dp_to_dp
table.
A one-to-one relationship is made up from:
Simply put, you need to relate the identical columns. Please see Which way should a Foreign Key go in a one to one relationship? for more information.
That said, to resolve the issue, remove the property public int LoteId { get; set; }
from Equipment class and relate their primary keys as follows:
Equipment model:
public class Equipment
{
public const string TableName = "ew_equipamento";
public int EquipmentId { get; set; }
//public int LoteId { get; set; } //TODO Remove
public LTE_dp_to_dp _Lote { get; set; }
}
LTE_dp_to_dp model:
public class LTE_dp_to_dp
{
public const string TableName = "ew_lte_cd_to_ft";
public int LoteId { get; set; }
public Equipment _Equipment { get; set; } //TODO Add
public List<LTE_dp_to_dp_Equipamento> _LoteEquipamentos { get; set; }
}
LTE_dp_to_dp_Equipamento model:
public class LTE_dp_to_dp_Equipamento
{
public const string TableName = "ew_lte_cd_to_ft_equipamento";
public int EquipmentLoteId { get; set; }
//public int EquipmentId { get; set; } //TODO Remove
//public Equipment _Equipment { get; set; } //TODO Remove
public int LoteId { get; set; }
public LTE_dp_to_dp _Lote { get; set; }
}
Equipment:
public void Configure(EntityTypeBuilder<Equipment> builder)
{
builder.ToTable(Equipment.TableName);
builder.HasKey(x => x.EquipmentId);
// Define a 1:1 relationship.
// You can define here or on the LTE_dp_to_dp config, but NOT on both!
builder.HasOne(x => x._Lote)
.WithOne(x => x._Equipment)
.HasForeignKey<LTE_dp_to_dp>(x => x.LoteId);
}
LTE_dp_to_dp:
public void Configure(EntityTypeBuilder<LTE_dp_to_dp> builder)
{
builder.ToTable(LTE_dp_to_dp.TableName);
builder.HasKey(x => x.LoteId);
}
LTE_dp_to_dp_Equipamento :
public void Configure(EntityTypeBuilder<LTE_dp_to_dp_Equipamento> builder)
{
builder.ToTable(LTE_dp_to_dp_Equipamento.TableName);
builder.HasKey(x => x.EquipmentLoteId);
// Define a 1:many relationship.
builder.HasOne(x => x._Lote)
.WithMany(x=> x._LoteEquipamentos)
.HasForeignKey(x => x.LoteId)
.OnDelete(DeleteBehavior.Restrict);
}
You don't need to define a one-to-one relationship between the LTE_dp_to_dp_Equipamento
and the Equipment
table as you can always access using the LTE_dp_to_dp
table. If you feel that you need to, then you may need to revise your data structure otherwise it is simply a bad design.
After migration your table structure should look as follows: