Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Are delete actions ignored by the Cosmos provider? #27572

Closed
julealgon opened this issue Mar 4, 2022 · 3 comments
Closed

Are delete actions ignored by the Cosmos provider? #27572

julealgon opened this issue Mar 4, 2022 · 3 comments

Comments

@julealgon
Copy link

I have a scenario where there is a 1:N relationship between 2 entities (mapped to 2 distinct containers in Cosmos). The relationship works fine on save/read: I have working endpoints where I fetch the parent object and the child entities are all loaded correctly.

I observed however that deleting the "parent" entity doesn't update the "foreign key" on the "child" entities in the other container.

I know Cosmos doesn't have the concept of a "foreign key" (thus the quotes), however my understanding was that the default action for this type of relationship was ClientSetNull on EF, which is purely controlled by the context and doesn't need support from the underlying database to work (at least that's what the description on the enum entry suggests to me). However, I tried configuring this setting explicitly but still the "foreign keys" are not cleared.

Are delete actions completely unsupported for the CosmosDB provider? Do I need to manually take care of this in application code when deleting the "parent" entity, or is there a way to set up the entity configuration in such a way that would do this automatically, like it does for SQL Server and other databases?

These are simplified versions of my entities:

class CodeRange
{
    public Guid Id { get; private set; }

    public int Start { get; set; }

    public int End { get; set; }

    public Guid? ReservationId { get; private set; }

    public Reservation? Reservation { get; set; }
}

class Reservation
{
    public Guid Id { get; set; }

    public ICollection<CodeRange> CodeRanges { get; } = new HashSet<CodeRange>();
}

I don't have the relationship configured explicitly since it was detected by default, but attempting to add it didn't result in any changes. Tried both from the Reservation entity:

builder
    .HasMany(r => r.CodeRanges)
    .WithOne(r => r.Reservation)
    .OnDelete(DeleteBehavior.ClientSetNull);

As well as from the CodeRange entity:

builder
    .HasOne(r => r.Reservation)
    .WithMany(r => r.CodeRanges)
    .OnDelete(DeleteBehavior.ClientSetNull);

And this is how I'm currently deleting the "parent" entity:

var reservationToDelete = await this.context.Reservations.FindAsync(reservationId);
if (reservationToDelete is not null)
{
    this.context.Reservations.Remove(reservationToDelete);
    await this.context.SaveChangesAsync();
}

This does 2 roundtrips but was an attempt to have EF set the nulls appropriately. This was my original code:

var reservationToDelete = new Reservation { Id = reservationId };
this.context.Reservations.Remove(reservationToDelete);
await this.context.SaveChangesAsync();

Which I assume should also work just fine (with a single roundtrip).

Provider and version information

EF Core version: 6.0.2
Database provider: Microsoft.EntityFrameworkCore.Cosmos
Target framework: NET 6.0

@julealgon
Copy link
Author

After more testing, I realized part of this is due to a misunderstanding on my part: I initially thought my relationships were "loading fine", but that was just because I was working on persisting new entries only.

After changing from FindAsync To SingleOrDefaultAsync in hopes that this would load the entities and make this work, I quickly realized it didn't change anything. Then, I tried adding an explicit .Include(r => r.CodeRanges) and that's when I realized the Cosmos provider doesn't support including non-owned entities like this.

I then experimented first with the lazy loading proxy, and then latter with an explicit load of the property, and both work as expected: if the entities are loaded in the context (one way or another), the relationship is properly updated and the "foreign key" is cleared on the children when I save the removal of the "parent".

Current (working) code:

        var reservationToDelete = await this.context.Reservations.FindAsync(reservationId);
        if (reservationToDelete is not null)
        {
            await this.context
                .Entry(reservationToDelete)
                .Collection(r => r.CodeRanges)
                .LoadAsync();

            this.context.Reservations.Remove(reservationToDelete);
            await this.context.SaveChangesAsync();
        }

I'd like to know if there is a more efficient way of achieving this however.

@ajcvickers
Copy link
Member

Note for triage: related to #16920.

@ajcvickers
Copy link
Member

Note from triage: this is covered by #16920. Closing as duplicate.

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants