Cannot insert into Many to Many relationship table

2019-08-24 21:13发布

I have the following objects: Most properties removed.

public class WorkQueue : IEntity
{
    public WorkQueue()
    {

    }

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

    public virtual ICollection<Action> Actions { get; set; }
    public virtual ICollection<Role> AllowableRoles { get; set; }
}

public class Role: IEntity
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public virtual ICollection<Action> Actions { get; set; }
    public virtual ICollection<WorkQueue> AllowedWorkQueues { get; set; }
}

public class Action: IEntity
{
    public Action()
    {
        Roles = new HashSet<Role>();
    }

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    public string Name { get; set; }


    public virtual Guid WorkQueue_Id { get; set; }
    public virtual WorkQueue WorkQueue { get; set; }

    public virtual ICollection<Role> Roles { get; set; }
}

And the following Entity Type Configurations:

public class WorkQueueConfig : EntityTypeConfiguration<WorkQueue>
{
    public WorkQueueConfig()
    {
        HasMany(x => x.AllowableRoles)
            .WithMany(x => x.AllowedWorkQueues)
            .Map(m =>
            {
                m.MapLeftKey("WorkQueueId");
                m.MapRightKey("RoleId");
                m.ToTable("AllowableRolesByWorkQueue");
            });

        HasMany(x => x.Actions)
            .WithRequired(x => x.WorkQueue)
            .WillCascadeOnDelete(false);
    }
}

public class ActionConfig: EntityTypeConfiguration<Action>
{
    public ActionConfig()
    {
        HasMany(x => x.Roles)
            .WithMany(x => x.Actions)
            .Map(m =>
            {
                m.MapLeftKey("ActionId");
                m.MapRightKey("RoleId");
                m.ToTable("ActionRole");
            });

        HasRequired(x => x.WorkQueue)
            .WithMany(x => x.Actions)
            .WillCascadeOnDelete(false);
    }
}

Which results in the following, which I am happy with:

enter image description here

The problem is, when I try and insert a new WorkQueue, my Role entries in the database gets duplicated. I have already INSERTED all of the possible Role entities.

I have read a few solutions, but none seems to work for me. I have tried the following:

Sending only the Id's of the Role's, to the DB. This did not work.

private async Task<WorkQueue> SetRolesAsPerContext(WorkQueue workQueue)
    {
        if (workQueue.AllowableRoles != null && workQueue.AllowableRoles.Count > 0)
        {
            ICollection<Role> roles = await _repository.GetAllAsync<Role>();
            IEnumerable<Guid> selectedRoleIds = workQueue.AllowableRoles.Select(s => s.Id);
            var filteredRoles = roles.Where(r => selectedRoleIds.Contains(r.Id))
                .Select(r => new Role() { Id = r.Id })
                .ToList();

            //set workqueue roles
            workQueue.AllowableRoles = filteredRoles;

            if (workQueue.Actions != null && workQueue.Actions.Count > 0)
            {
                foreach (SimO2O.Models.Action action in workQueue.Actions)
                {
                    IEnumerable<Guid> selectedActionRoleIds = action.Roles.Select(s => s.Id);
                    action.Roles = roles.Where(r => selectedActionRoleIds
                        .Contains(r.Id))
                        .Select(r => new Role() { Id = r.Id })
                        .ToList();
                }
            }
        }

        return workQueue;
    }

I have also tried attaching the Role objects to the current context, so that EntityFramework will not see them as new objects, and finally, tried setting the EntityState to Detached, but this continues to create duplicate Roles.

public async Task<Guid> CreateWorkQueueAsync(WorkQueue workQueue, string userName)
    {
        //set Permissions on same context
        _repository.AttachEntity(workQueue.AllowableRoles);
        _repository.ModifyState(workQueue.AllowableRoles, System.Data.Entity.EntityState.Detached);

        _repository.Create(workQueue, workQueue.AllowableRoles, userName);
        await _repository.SaveAsync();
        return workQueue.Id;
    }

Below are the methods I wrote in the _repository class for attaching and setting the EntityState.

public void AttachEntity<TEntity>(TEntity entity) where TEntity : class, IEntity
    {
        Context.Set<TEntity>().Attach(entity);
    }

    public void AttachEntity<TEntity>(ICollection<TEntity> entities) where TEntity : class, IEntity
    {
        foreach (TEntity entity in entities)
            Context.Set<TEntity>().Attach(entity);
    }

    public void ModifyState<TEntity>(TEntity entity, EntityState state) where TEntity : class, IEntity
    {
        Context.Entry(entity).State = state;
    }

    public void ModifyState<TEntity>(ICollection<TEntity> entities, EntityState state) where TEntity : class, IEntity
    {
        foreach (TEntity entity in entities)
            Context.Entry(entity).State = state;
    }

What am I missing here?

0条回答
登录 后发表回答