Home > Software engineering >  Inserting of foreign key object inserts new object
Inserting of foreign key object inserts new object

Time:04-04

When I insert a new MaskField model into my database using Entity Framework Core it also inserts a Restriction model which is referenced inside the MaskField model. I am trying to get it to only reference a Restriction object as I already know the object exists when trying to reference it inside MaskField.

I have a MaskField model defined:

[Table("MaskField", Schema = "dbo")]
public class MaskField
{
    [Key]
    public int maskId { get; set; }
        public Restriction? restriction { get; set; }
}

That MaskField model references a single Restriction model inside it. This is the Restriction model:

[Table("Restriction", Schema = "dbo")]
public class Restriction
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int restrictionId { get; set; }
    [Required]
    public string? restrictionName { get; set; }
    [Required]
    public string? regex { get; set; }
}

My DbContext:

public class MaskContext : DbContext
{
    public MaskContext(DbContextOptions options) : base(options) { }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MaskField>((mf) =>
        {
            mf.HasKey(e => new { e.maskId });
            mf.HasOne(e => e.restriction).WithMany();
        });
    }

    public DbSet<MaskField> MaskFields { get; set; }
    public DbSet<Restriction> Restrictions { get; set; }
}

Trying to insert a MaskField that contains a restriction ends up executing:

INSERT INTO [dbo].[Restriction] ([restrictionId], [regex], [restrictionName])
VALUES (@p0, @p1, @p2); 

Which ends up erroring because IDENTITY_INSERT is disabled. Any ideas on how to just reference it instead of it trying to insert a new Restriction model?

EDIT: This is the code for inserting a MaskField

public class MaskRepository : IMaskRepository
{
    MaskContext dbContext;
    public MaskRepository(MaskContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public async Task<MaskField> CreateAsync(Mask _object)
    {
        var obj = await dbContext.MaskFields.AddAsync(_object);
        dbContext.SaveChanges();
        return obj.Entity;
    }
}

CodePudding user response:

I have found a not so nice workaround for this.

So to just reference the Restriction is fairly simple just change the line public Restriction? restriction {get;set;} to reference the key for Restriction like: public int? restrictionId {get;set;}

However since I wanted to extract the whole Restriction object in the one query I was forced to have both fields like this:

[Table("MaskField", Schema = "dbo")]
public class MaskField
{
    [Key]
    public int maskId { get; set; }
    
    public int? restrictionId { get; set; }
    public Restriction? restrictionId { get; set; }
}

This seems like a good solution until I realised that when saving/ updating that object to the database it causes the same original problem.

To work around this I have added logic in the saving and updating functions to set those fields to null before saving:

public class MaskRepository : IMaskRepository
{
    MaskContext dbContext;
    public MaskRepository(MaskContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public async Task<MaskField> CreateAsync(MaskField _object)
    {
        _object.restriction = null;

        var obj = await dbContext.MaskFields.AddAsync(_object);
        dbContext.SaveChanges();
        return obj.Entity;
    }
}

CodePudding user response:

Finally found a proper resolution to this problem. You can add the [JsonIgnore] field to model classes to stop models from even being submitted to ef core in the first place.

In this case it will be:

[Table("MaskField", Schema = "dbo")]
public class MaskField
{
    [Key]
    public int maskId { get; set; }
    
    public int? restrictionId { get; set; }
    [JsonIgnore]
    public Restriction? restriction { get; set; }
}
  • Related