Entity framework MVC 3 EF 4.1 dbContext-删除具有不可空外键关系的一对多数据对象

Entity framework MVC 3 EF 4.1 dbContext-删除具有不可空外键关系的一对多数据对象,entity-framework,asp.net-mvc-3,Entity Framework,Asp.net Mvc 3,我使用的是MVC3、EF4.1和dbContext。我需要知道如何删除与不可空外键存在一对多关系的实体 当我删除子实体并执行SaveChanges时,会出现以下错误: 操作失败:无法更改关系,因为一个或多个外键属性不可为null。对关系进行更改时,相关外键属性设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象 从其他帖子中,我了解到使用Remove(entity)将实体标记为delete。在SaveChanges期间,EF将外键设置为Nu

我使用的是MVC3、EF4.1和dbContext。我需要知道如何删除与不可空外键存在一对多关系的实体

当我删除子实体并执行SaveChanges时,会出现以下错误:

操作失败:无法更改关系,因为一个或多个外键属性不可为null。对关系进行更改时,相关外键属性设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象

从其他帖子中,我了解到使用Remove(entity)将实体标记为delete。在SaveChanges期间,EF将外键设置为Null,并出现上述错误

我发现一些帖子在子实体上使用DeleteObject而不是Remove;然而,由于添加了dbContext和DbSet,DeleteObject方法似乎已被放弃

我发现有帖子建议将EDMX外键关系修改为可空。修改EDMX是可以的,但每当数据库的更新模型完成时,这些更改都会被取消,必须重新应用。不是最优的

另一篇帖子建议创建一个外键关系设置为Nullable的代理实体,但我不理解这种方法。它似乎遇到了与修改EDMX相同的问题,即当保存对EDMX的更改时,上下文会自动更新

我的简化模型是:

public partial class User
{
    public User()
    {
        this.UserContacts = new HashSet<UserContact>();
    }

    public long userId { get; set; }
    public string userEmail { get; set; }
    public string userPassword { get; set; }
    public string userFirstName { get; set; }
    public string userLastName { get; set; }
     . . .
    public virtual Country Country { get; set; }
    public virtual State State { get; set; }
    public virtual ICollection<UserContact> UserContacts { get; set; }
}
userContactUserId和userContactTypeId是必需的外键

在dbContext容器中,用户和用户联系人都是DbSet

我有一个用于用户的ViewModel和一个用于UserContact的ViewModel,如下所示

public class UserContactViewModel
{
    [HiddenInput]
    public long UserContactId { get; set; }

    [HiddenInput]
    public long UserContactUserId { get; set; }

    [Display(Name = "Contact")]
    [Required]
    public string ContactData { get; set; }

    [Required]
    public long ContactType { get; set; }

    [HiddenInput]
    public bool isDeleted { get; set; }

}

    public class MyProfileViewModel
    {

        [HiddenInput]
        public long UserId { get; set; }

        [Required]
        [Display(Name = "First Name")]
        [StringLength(100)]
        public string FirstName { get; set; }

        [Required]
        [StringLength(100)]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        ....
        public IEnumerable<UserContactViewModel> Contacts { get; set; }

}

非常感谢您的帮助。

您可以将关系配置为级联。。。这将把删除传播到依赖实体

但这非常危险:)


我更喜欢在行中设置一个标志,以防止数据层在将来的查询中包含它,大多数应用程序不需要物理删除(并且将有机会撤消)。

好的,实现您自己的ICollection,并在删除这些子对象的同时将其标记为删除。然后,在您自己的SaveChanges方法覆盖中,删除这些对象。

我在MSDN指南页面的“关系级联删除规则”一节中解决了相同的问题
希望你能有所帮助:D

我设法解决了这个问题,如下所示:

首先,我能够通过将DbContext(例如“ctx”)强制转换为IObjectContextAdapter,然后获取对ObjectContext的引用来获取ObjectContext

接下来,我简单地调用DeleteObject方法来传递要删除的UserContact记录

当SaveChanges获得时,数据库中的删除将按预期进行

if (c.isDeleted == true)  // Deleted UserContact
{
    ObjectContext oc = ((IObjectContextAdapter)ctx).ObjectContext;
    oc.DeleteObject(uc)
}
以下是相关代码的片段:

foreach (var c in model.Contacts)
{
    UserContact uc = null;
    if (c.UserContactId != 0)
    {
        uc = ctx.UserContacts.Find(c.UserContactId);
    }
    if (uc != null)
    {
        if (c.isDeleted == true)  // Deleted UserContact
        {
            ObjectContext oc = ((IObjectContextAdapter)ctx).ObjectContext;
            oc.DeleteObject(uc);
        }
        else  //  Modified UserContact
        {
            uc.userContactData = c.ContactData;
            uc.userContactTypeId = c.ContactType;
            ctx.Entry(uc).State = EntityState.Modified;
        }
    }
    else  // New UserContact
    {
        usr.UserContacts.Add(new UserContact { userContactData = c.ContactData, userContactTypeId = c.ContactType });
    }
}

ctx.Entry(usr).State = EntityState.Modified;
ctx.SaveChanges();

希望这对将来的人有所帮助。

你有没有找到解决办法?我也有同样的问题,你找到解决办法了吗?我也有同样的问题?@BZ你找到解决办法了吗?我也有同样的问题?我确实找到了解决办法,请参阅下面我的回答帖子。
if (c.isDeleted == true)  // Deleted UserContact
{
    ObjectContext oc = ((IObjectContextAdapter)ctx).ObjectContext;
    oc.DeleteObject(uc)
}
foreach (var c in model.Contacts)
{
    UserContact uc = null;
    if (c.UserContactId != 0)
    {
        uc = ctx.UserContacts.Find(c.UserContactId);
    }
    if (uc != null)
    {
        if (c.isDeleted == true)  // Deleted UserContact
        {
            ObjectContext oc = ((IObjectContextAdapter)ctx).ObjectContext;
            oc.DeleteObject(uc);
        }
        else  //  Modified UserContact
        {
            uc.userContactData = c.ContactData;
            uc.userContactTypeId = c.ContactType;
            ctx.Entry(uc).State = EntityState.Modified;
        }
    }
    else  // New UserContact
    {
        usr.UserContacts.Add(new UserContact { userContactData = c.ContactData, userContactTypeId = c.ContactType });
    }
}

ctx.Entry(usr).State = EntityState.Modified;
ctx.SaveChanges();