0

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.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

0 Answers0