I have these classes in my project (the names in the code are in Portuguese, if necessary I can translate) :
public class EntityWithGuid : IEntityWithId<string>
{
protected EntityWithGuid()
{
this.Id = Guid.NewGuid().ToString("N").ToLower();
}
[Key]
public string Id { get; set; }
}
public class Servico : EntityWithGuid
{
public DateTime? Data { get; set; }
public string Descricao { get; set; }
public string Cliente_Id { get; set; }
[ForeignKey("Cliente_Id")]
public Cliente Cliente { get; set; }
[Required]
public ICollection<ServicoImagem> Imagens { get; set; }
[Required]
public ICollection<Tag> Tags { get; set; }
}
public class ServicoImagem : EntityWithGuid
{
[Required]
public string Nome { get; set; }
public string Servico_Id { get; set; }
[Required]
public Servico Servico { get; set; }
}
public class Tag : EntityWithGuid
{
[Required]
public string Nome { get; set; }
public string Fonetica { get; set; }
public ICollection<Servico> Servicos { get; set; }
}
And this is the Context
configuration:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ServicoConfiguration());
}
internal class ServicoConfiguration : EntityTypeConfiguration<Servico>
{
internal ServicoConfiguration()
{
this.HasMany(s => s.Tags)
.WithMany(t => t.Servicos)
.Map(mf =>
{
mf.MapLeftKey("Servico_Id");
mf.MapRightKey("Tag_Id");
mf.ToTable("ServicoTag");
});
this.HasMany(s => s.Imagens)
.WithRequired(i => i.Servico)
.HasForeignKey(f => f.Servico_Id);
}
}
After load a Servico
entity the update method can do any operation with the Servico.Tags
property (add and remove items), mark as modified and finally call Context.SaveChanges()
. Everything works perfectly.
var servico = Context.Set<Servico>()
.Include(x => x.Cliente)
.Include(x => x.Tags)
.Include(x => x.Imagens)
.FirstOrDefault(x => x.Id == id);
...
// Remove tags
servico.Tags = servico.Tags.Except(oldTags).ToList();
// Add new tags
servico.Tags = servico.Tags.Concat(newTags).ToList();
...
Context.Entry(servico).State = EntityState.Modified;
Context.SaveChanges();
If I do the same thing with the Images property is only possible to make one type of operation at a time, add OR remove. If added and removed at the same time, the added item does not receive the value of the foreign key and error occurs in Context.SaveChanges()
but if I do only one type of operation, it works perfectly.
The only solution I found was to make a loop to mark the item as deleted.
// Mark image as deleted
foreach (var imagem in imagensParaDeletar)
{
Context.Entry(imagem).State = System.Data.Entity.EntityState.Deleted;
}
I would like to understand why the problem ONLY occurs in this type of relationship and ONLY when I need to do both type of operation on the same property.