【问题标题】:Setting a Foreign Key Value Back to Null in Entity Framework在实体框架中将外键值设置回 Null
【发布时间】:2014-08-06 00:17:23
【问题描述】:

从记录中删除外键值时,我无法将记录保存到 SQL Server 数据库。

例如,我有一个现有的 BatchDetail 记录,主键 BatchDetailID = 10。它与现有的 RunDetail 记录相关联,主键 RunDetailID = 20,外键 BatchDetailID = 10。我想通过将 RunDetails.BatchDetailID 设置为 null 来解除 RunDetail 与 BatchDetail 的关联。

这是错误信息:

发生参照完整性约束违规:关系一端的“BatchDetail.BatchDetailID”的属性值与另一端的“RunDetail.BatchDetailID”的属性值不匹配。

这是我的类定义:

public class RunDetail
{
    public int RunDetailID { get; set; }
    public Nullable<int> BatchDetailID { get; set; }

    public virtual BatchDetail BatchDetail { get; set; }
}

public class BatchDetail
{
    public int BatchDetailID { get; set; }

    public virtual ICollection<RunDetail> RunDetails { get; set; }
}

RunDetail 对象具有BatchDetailID 值时发生错误,我尝试将其设置回null:

public class MyController : Controller
{
    private ISvr _myService;

    public ISvr MyService
    {
        get { return _myService ?? (_myService = new MyHandler().GetMyService()); }

        set
        {
            _myService = value;
        }
    }

    public void UpdateBatch(int id)
    {
        foreach (var batchDetail in MyService.ReadBatchDetails(id))
        {
            var runDetail = MyService.ReadRunDetail(batchDetail.RunDetailID);

            runDetail.BatchDetailID = null;
            runDetail.BatchDetail = null; // I have tried with, and without, this line

            MyService.UpdateRun(runDetail );
        }
    }
}

public class MyHandler
{
    public ISvr GetMyService()
    {
        return new MySvr();
    }
}

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
public class MySvr : IMySvr
{
    public void UpdateRun(RunDetail runDetail)
    {
        using (var myEntities = new MyEntities())
        {
            myEntities.RunDetails.Attach(runDetail); // This is where the exception hits
            myEntities.Entry(runDetail).State = EntityState.Modified;
            myEntities.SaveChanges();
        }
    }
}

所有其他记录更新,包括将外键值更改为另一个,都可以正常工作。

谁能看出我的缺点是什么?

【问题讨论】:

  • BatchDetailID 不能为空,你怎么能这样设置runDetail.BatchDetailID = null; ??
  • @YuliamChandra 谢谢,这是我在转录原始代码时犯的一个错误。我现在已经在上面更新以反映Nullable&lt;int&gt;

标签: c# entity-framework crud


【解决方案1】:

问题的根源在于我的问题中没有包含的方法。当我检索父 BatchDetail 记录时,我包含了“RunDetails”记录:

public List<BatchDetail> ReadBatchDetails(int id)
{
    using (var myEntities = new MyEntities())
    {
        return myEntities.BatchDetails
            .Include("RunDetails") // This is the problem
            .AsNoTracking().ToList();
    }
}

通过创建不Include("RunDetails")的新方法,问题解决了:

public List<BatchDetail> ReadBatchDetailsWithoutRunDetails(int id)
{
    using (var myEntities = new MyEntities())
    {
        return myEntities.BatchDetails.AsNoTracking().ToList();
    }
}

【讨论】:

    【解决方案2】:

    我插入了 1 个 BatchDetail 和 1 个 RunDetail,如下所示。

    using (var db = new AppContext())
    {
        db.BatchDetails.Add(new BatchDetail { Id = 1 });
        db.RunDetails.Add(new RunDetail { Id = 1, BatchDetailId = 1 });
        db.SaveChanges();
    }
    

    那么这里就是抛出同样错误的结果。

    using (var db = new AppContext())
    {
        // This is okay.
        var x = new RunDetail { Id = 1, BatchDetailId = 1, BatchDetail = new BatchDetail { Id = 1 } };
        db.RunDetails.Attach(x);
    }
    using (var db = new AppContext())
    {
        // This is okay.
        var x = new RunDetail { Id = 1, BatchDetailId = null, BatchDetail = null };
        db.RunDetails.Attach(x);
    }
    using (var db = new AppContext())
    {
        // This is okay.
        var x = new RunDetail { Id = 1, BatchDetailId = 1, BatchDetail = null };
        db.RunDetails.Attach(x);
    }
    using (var db = new AppContext())
    {
        // A referential integrity constraint violation occurred: The property 
        // value(s) of 'BatchDetail.Id' on one end of a relationship do not match the property 
        // value(s) of 'RunDetail.BatchDetailId' on the other end.
        var x = new RunDetail { Id = 1, BatchDetailId = null, BatchDetail = new BatchDetail { Id = 1 } };
        db.RunDetails.Attach(x);
    }
    

    在你的情况下应该是一样的。

    【讨论】:

    • 我更新了我的问题以提供示例场景。插入新记录没有问题。错误是当我想解除 RunDetail 记录与 BatchDetail 记录的关联时。
    • @ChrisSchiffhauer,您能否检查 EchidnaSvr::UpdateRun 上的值 BatchDetailIDBatchDetail 变量上的 runDetail 属性值是否与我在最后一部分的答案中的值相似( FK ID 为 null,但 FK 引用不为 null)
    • 谢谢。 RunDetail 对象同时具有 BatchDetailBatchDetailID,当它被传递到 UpdateRun 时,其值为 null。而且我无法设置RunDetail.BatchDetail = new BatchDetail { BatchDetailID = null }
    猜你喜欢
    • 2017-01-06
    • 2018-10-25
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    • 2022-11-19
    • 2021-09-03
    • 2023-04-11
    相关资源
    最近更新 更多