0

I am making code first entity framework database model, and I am struggeling with cascade delete. There are my simple classes:

public class User {
    [Key()]
    public int Id {get; set;}
    public string Name {get; set;}

    public int CampaignId {get; set;}
    [ForeignKey("CampaignId")]
    public virtual Campaign Campaign {get; set;}
}

public class Campaign {
    [Key()]
    public int Id {get; set;}
    public string Description {get; set;}

    public virtual List<User> Users {get; set;}

    public Campaign() {
        Users = new List<User>();
    }
}

The basic idea is to assign one campaign to every user. When I delete campaign which is assigned by user:

internal static void DeleteCampaign(Campaign campaignToDelete) {
            using (var context = new DatabaseContext()) {
                context.Entry(campaignToDelete).State = EntityState.Deleted;
                context.SaveChanges();
            }
        }

Users assigned to that campaign are deleted too. What I want is to not delete users, but assign them to first avaible campaign, or null. For some reason I cant do something like that:

internal static void DeleteCampaign(Campaign campaignToDelete) {
            using (var context = new DatabaseContext()) {

                for (int i = 0; i < campaignToDelete.Users.Count; i++) {
                    campaignToDelete.Users[i].Campaign = context.Campaigns.ElementAt(0);
                }

                context.Entry(campaignToDelete).State = System.Data.Entity.EntityState.Deleted;
                context.SaveChanges();
            }
        }

Because I am getting error:

An unhandled exception of type 'System.ObjectDisposedException' occurred in EntityFramework.dll

Additional information: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

So how can I avoid that?

2 Answers2

0

Lazy loading should be enabled by default when using virtual.

This may be helpful: How to disable cascade delete for link tables in EF code-first?

LadyHail
  • 91
  • 1
  • 5
0

1) What kind of object do you pass to the DeleteCampaign method? I think that is one of your entity framwork proxy models, which was queried by another database context. You access in your for-loop the linked User object, which could not be loaded because the context doesn't exist anymore.

for (int i = 0; i < campaignToDelete.Users.Count; i++) {

Don't mix objects of different database contexts.

Better way is, that you pass the ID of the Campaign to the DeleteCampaign method and then you have to query the campaign in the new database context. After that you can do all operations in one using statement (= the same database context).

static void DeleteCampaign(int idOfCampaignToDelete)
    {
        using (var context = new DatabaseContext())
        {
            var campaignToDelete = context.Campaigns.FirstOrDefault(c => c.Id == idOfCampaignToDelete);
            for (int i = 0; i < campaignToDelete.Users.Count; i++)
            {
                campaignToDelete.Users[i].Campaign = context.Campaigns.ElementAt(0);
            }

            context.Entry(campaignToDelete).State = System.Data.Entity.EntityState.Deleted;
            context.SaveChanges();
        }
    }

2) You cannot use ElementAt(0) in a LINQ to Entities query. Use .FirstOrDefault().

campaignToDelete.Users[i].Campaign = context.Campaign.FirstOrDefault();

3) Make the CampaignId in your User class nullable. Otherwise you cannot have Users without Campaigns, because the Foreign Key would not be nullable.

public int? CampaignId {get; set;}

Now your code should work.

Marco
  • 21
  • 4