【问题标题】:Set to default instead delete cascade设置为默认值而不是删除级联
【发布时间】:2018-03-30 19:35:18
【问题描述】:

我正在制作代码优先实体框架数据库模型,并且正在与级联删除作斗争。有我的简单课程:

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>();
    }
}

基本思想是为每个用户分配一个广告系列。当我删除用户分配的活动时:

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

分配给该广告系列的用户也会被删除。我想要的是不删除用户,而是将它们分配给第一个可用的活动,或者为空。出于某种原因,我不能这样做:

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();
            }
        }

因为我收到错误:

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.

那我该如何避免呢?

【问题讨论】:

  • 你开启延迟加载了吗?

标签: c# entity-framework


【解决方案1】:

1) 你传递给 DeleteCampaign 方法的对象是什么? 我认为这是您的实体框架代理模型之一,它由另一个数据库上下文查询。 您在 for 循环中访问链接的 User 对象,该对象无法加载,因为上下文不再存在。

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

不要混合不同数据库上下文的对象。

更好的方法是,您将活动的 ID 传递给 DeleteCampaign 方法,然后您必须在新的数据库上下文中查询活动。 之后,您可以在一个 using 语句中执行所有操作(= 相同的数据库上下文)。

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) 不能在 LINQ to Entities 查询中使用 ElementAt(0)。 使用 .FirstOrDefault()。

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

3) 使您的 User 类中的 CampaignId 可以为空。否则,您将无法拥有没有营销活动的用户,因为外键不能为空。

public int? CampaignId {get; set;}

现在您的代码应该可以工作了。

【讨论】:

    【解决方案2】:

    使用virtual时默认开启延迟加载。

    这可能会有所帮助: How to disable cascade delete for link tables in EF code-first?

    【讨论】:

      猜你喜欢
      • 2014-02-16
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      • 2017-12-07
      • 1970-01-01
      • 2017-07-31
      • 1970-01-01
      相关资源
      最近更新 更多