0

I have two objects. Profile and ProfileImage. My context is set up to fetch a Profile and I want to delete a ProfileImage (not just the reference) through the Profile, first fetching the profile then getting a profileImage and removing it like this:

using (var dbContext = new myContext())
        {
            var profile = dbContext.profiles.Where(i => i.ApplicationUserGuid == userId).First();

            var profileImageToDelete = profile.profileImages.Where(i => i.YogaProfileImageId == Convert.ToInt32(idToRemove)).First();

            profile.ProfileImages.Remove(profileImageToDelete);

            dbContext.SaveChanges();
        }

But I'm getting an error when saving that says:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

Here are my two entity objects:

public class Profile
{
    public Profile()
    {
        ProfileImages = new List<ProfileImage>();
    }

    [Key]
    public int ProfileId { get; set; }

    [Column(TypeName = "VARCHAR")]
    [StringLength(36)]
    [Index]
    public string ApplicationUserGuid { get; set; }

    public bool IsActive { get; set; }

    public virtual ICollection<ProfileImage> ProfileImages { get; set; } //one-to-many }


public class ProfileImage
{
    [Key]
    public int ProfileImageId { get; set; }
    public int ProfileRefId { get; set; }
    [ForeignKey("ProfileRefId")]
    public virtual Profile Profile { get; set; }
    public byte[] CroppedImage { get; set; }
    public byte[] ImageThumbnailCropped { get; set; }
    public bool IsMainImage { get; set; }
}

I read something about cascading deletes but not sure if this is what I need to do or what I need to do to get the image to delete completely from the ProfileImage table.

chuckd
  • 13,460
  • 29
  • 152
  • 331
  • Well you delete an item, no other item should reference it or the cascading rule should be set as appropriate. – Phil1970 Nov 05 '16 at 03:13
  • what does that mean and what , if anything, should I change? – chuckd Nov 05 '16 at 08:54
  • Well, it is up to you to fix the database design as appropriate or figure out why you cannot delete an item... The reason and solution are specific to each application. Sometime, you might want to delete any object pointing to that object. Sometime, you want to set a null link. Sometime, you want to prevent that. And sometime, you might have to do it manually in code if there are some loops or complex logic. **In you case, you have to remove the image from the profile using cascade delete or your own code as otherwise the profile would have a non existing image.** – Phil1970 Nov 06 '16 at 03:01

2 Answers2

2

Try adding:

dbContext.Entry(profileImageToDelete).State = EntityState.Deleted;

Before applying dbContext.SaveChanges();

middelpat
  • 2,555
  • 1
  • 20
  • 29
Faisal
  • 123
  • 1
  • 10
  • More details: http://stackoverflow.com/questions/19325473/ef6-0-the-relationship-could-not-be-changed-because-one-or-more-of-the-foreign – Faisal Nov 05 '16 at 02:52
  • this worked, but what does it mean and why did I have to use it? – chuckd Nov 05 '16 at 09:02
2

The entitystatetracker doesn't see anything modified to your profileImage, so the removing of this entity from the in memory collection isn't saved back to the database.

As Faisal mentioned you can let the entitystatetracker know that the object should be deleted from the database by setting it's entitystate to deleted:

dbContext.Entry(profileImageToDelete).State = EntityState.Deleted;

However instead of marking it as deleted, you could also use:

dbContext.profileImages.Remove(profileImageToDelete);
dbContext.SaveChanges();
middelpat
  • 2,555
  • 1
  • 20
  • 29