简体   繁体   中英

Entity Framework 6.x cannot remove an attached entity in a relationship

I have a pretty simple auction-like application. Using EF 6.x and am getting a ton of strange behavior when trying to delete a child (Bid) from the parent (Listing). I'm deleting entities with similar types of relationships, elsewhere in my application, without any problems. The entities involved:

public class Listing {
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ListingID { get; set; }

    [Required]
    public bool Active { get; set; }

    [Required]
    [StringLength(128)]
    public string UserID { get; set; }

    [ForeignKey("UserID")]
    public ApplicationUser User { get; set; }

    public List<Bid> Bids { get; set; }

    public Listing() {
        User = new ApplicationUser();
        Bids = new List<Bid>();
    }
}

public class Bid {
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int BidID { get; set; }

    [Required]
    public decimal Amount { get; set; }

    [Required]
    public DateTime Created { get; set; }

    [Required]
    [StringLength(128)]
    public string UserID { get; set; }

    public int ListingID { get; set; }

    [ForeignKey("UserID")]
    public ApplicationUser User { get; set; }

    [ForeignKey("ListingID")]
    public Listing Listing { get; set; }

    public Bid() {
        User = new ApplicationUser();
        Listing = new Listing();
    }
}

public class ApplicationUser : IdentityUser {
    public List<Listing> Listings { get; set; }

    public List<Bid> Bids { get; set; }

    public ApplicationUser() {
        Listings = new List<Listing>();
        Bids = new List<Bid>();
    }
}

In this particular context, I'm querying out the bids by user and removing them:

public bool RemoveBids(string offenderUserID) {
    using (var db = new MyDbContext()) {
        var bids = db.Bids
            .Include(l => l.Listing)
            .Where(x => x.UserID == offenderUserID && x.Listing.Active == true);

        foreach (var bid in bids) {
            bid.User = null;
            bid.Listing = null;
            db.Bids.Remove(bid);
            db.Entry(bid).State = EntityState.Deleted;
        }

        return db.SaveChanges() == 1 ? true : false; //exception on SaveChanges()
    }
}

Until I nulled the bid.Listing, I got a DbEntityValidationException saying the fields for the Listing are required. Walking through it in the debugger shows that EF tries to add new entities to bid.User and bid.Listing. Crazy...but OK. I kept going w/ it and ended up with what you see above...which results in another xxx of:

The UserName field is required.

UserName is in IdentityUser (AspNetUsers table) as part of Identity Framework.

It's still trying to add an ApplicationUser...somehow, somewhere? Nowhere in the graph I queried above is there an ApplicationUser object. I just don't see it.

Inspecting the tables shows the fields to be exactly like the entities above.

This is my first non-trivial Code-First project. I've worked on a few rather large DB-First projects w/ edmx models and never remember hitting so many snags and weird "gotchas". Most things just seemed to work. Should I just convert the thing? I've wasted too much time on something so simple, as it is. I want to like EF. I like the idea of it...but not feeling particularly productive, after days of troubleshooting.

Thanks in advance.

public Bid() {
    User = new ApplicationUser();
    Listing = new Listing();
}

public Listing() {
    User = new ApplicationUser();
    Bids = new List<Bid>();
}

EDIT . The above code is just wrong. Remove those initializers. They should only exist for collections. The reason you are getting those bizarre errors is because every time you are loading a Bid or Listing object, you are creating brand new objects that are missing required parameters, thus when calling savechanges, you end up with EF complaining that certain required parameters are missing.

I initially see this as a property of the Bid class.

public int ListingID

But then you have...

bid.Listing = null;

Logically, this doesn't make any sense. In the first line of code, you are saying that the Listing property is required for every bid. But by setting it to null, you are saying that "this listing is not required for this bid".

I think you can just safely remove the the lines of code where you set the navigation properties to null as they accomplish nothing, since you are just deleting the Bid object anyway.

I had a similar issue and for me, it looked like I hadn't correctly established the relationship between Parent and Child in their respective classes.

My fix was to add the attributes specified below to the Child class, for the property that represented its Parent's Id

public class Child
{
    [Key, Column(Order = 1)]
    public string Id { get; set; }

    [Key, ForeignKey("Parent"), Column(Order = 2)]  // adding this line fixed things for me
    public string ParentId {get; set;}
}

public class Parent
{
    [Key, Column(Order = 1)]
    public string Id { get; set; }

    ...

    public virtual ICollection<Child> Children{ get; set; }
}

Looking at your code, it looks like in the Bid class, its parent is ListingId?

If so, that would be the line to modify as follows:

[Key, ForeignKey("Listing"), Column(Order = 2)]
public int ListingID { get; set; }

After doing that, I was also able to remove the following line, so only the .Remove call was required:

db.Entry(bid).State = EntityState.Deleted;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM