Deleting a listing in table throws a SQL error

0

I have a .NetCore Entity Framework project for a model airport.

When I try to delete an airport in the listings, I am getting the error below when trying to delete an airline and I'm trying to figure out why:

Microsoft.Data.SqlClient.SqlException (0x80131904): The DELETE statement conflicted with the REFERENCE constraint "FK_airlinePilots_airline". The conflict occurred in database "FrankAirportTeam", table "dbo.airlinePilots", column 'airlineId'.

The delete action is just an API method:

    [HttpDelete("{id}")]
    public async Task<ActionResult<Airline>> DeleteAirline(long id)
    {
        var airline = await _context.Airline.FindAsync(id);
        if (airline == null)
        {
            return NotFound();
        }

        _context.Airline.Remove(airline);
        await _context.SaveChangesAsync();

        return airline;
    }

My model for Airline is here below:

public partial class Airline
{
    public Airline()
    {
        AirlinePilots = new HashSet<AirlinePilots>();
    }

    public long Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public long CityId { get; set; }

    public virtual City City { get; set; }
    public virtual ICollection<AirlinePilots> AirlinePilots { get; set; }
}

And AirlinePilots

    public partial class AirlinePilots
{
    public long PilotId { get; set; }
    public long AirlineId { get; set; }

    public virtual Airline Airline { get; set; }
    public virtual Pilot Pilot { get; set; }
}

My DB context class looks like this for Airline:

modelBuilder.Entity<Airline>(entity =>
        {
            entity.ToTable("airline");

            entity.HasIndex(e => e.Id)
                .HasName("IX_airline");

            entity.Property(e => e.Id)
                .HasColumnName("id");

            entity.Property(e => e.Description)
                .IsRequired()
                .HasColumnName("description");

            entity.Property(e => e.CityId).HasColumnName("cityId");

            entity.Property(e => e.Title)
                .IsRequired()
                .HasColumnName("title")
                .HasMaxLength(255);

            entity.HasOne(d => d.City)
                .WithMany(p => p.Airline)
                .HasForeignKey(d => d.CityId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_airline_city");
        });

And on AirlinePilots [UPDATED WITH NEW DELETE METHOD]:

        modelBuilder.Entity<AirlinePilots>(entity =>
        {
            entity.HasKey(e => new { e.PilotId, e.AirlineId });

            entity.ToTable("airlinePilots");

            entity.Property(e => e.PilotId).HasColumnName("pilotId");

            entity.Property(e => e.AirlineId).HasColumnName("airlineId");

            entity.HasOne(d => d.Airline)
                .WithMany(p => p.AirlinePilots)
                .HasForeignKey(d => d.AirlineId)
                .OnDelete(DeleteBehavior.Cascade)
                .HasConstraintName("FK_airlinePilots_airline");

            entity.HasOne(d => d.Pilot)
                .WithMany(p => p.AirlinePilots)
                .HasForeignKey(d => d.PilotId)
                .OnDelete(DeleteBehavior.Cascade)
                .HasConstraintName("FK_airlinePilots_pilot");
        });

AirlinePilots is just a lookup table that stores a AirlineId for each PilotId. One Airline can have many Pilots. It has a foreign key for AirlineId and one for PilotId.

In my database, the Airline doesn't have a foreign key for AirlinePilots. However, the AirlinePilots table does have a foreign key for Airline.

So, the DELETE action in the API would need to delete the Airline and any associated rows that contain the Airline Id being deleted in the AirlinePilots table.

I'm actually really scared to change anything because I don't want it to accidently delete everything in the AirlinePilots table.

Is there anything I can add to my context class to make this work?

thanks! :)

entity-framework
asp.net-core
entity-framework-core
asp.net-core-webapi
asp.net-core-3.0
asked on Stack Overflow Apr 24, 2020 by SkyeBoniwell • edited Apr 27, 2020 by SkyeBoniwell

1 Answer

3

AirlineId is not a nullable foreign key on AirlinePilots, so you can't use ClientSetNull because it throws on SaveChanges, what you need is a cascading deletion behavior which is achieved using Cascade option for Airline fk mapping.:

.OnDelete(DeleteBehavior.Cascade) 

Btw, from your mapping I get you are also controlling this collection from Pilot entity, usually this is a design flaw that can cause you troubles down the road, you might end having the same item loaded twice in memory pointing to the same database row, where concurrencies issues might pop out. If you need to show the airlines from Pilot then use a query to return read only entities instead.

answered on Stack Overflow Apr 24, 2020 by E-Bat

User contributions licensed under CC BY-SA 3.0