C# 实体框架未在附加时保存记录-在添加时保存重复的导航属性

C# 实体框架未在附加时保存记录-在添加时保存重复的导航属性,c#,.net,winforms,entity-framework,C#,.net,Winforms,Entity Framework,我正在开发一个带有实体框架的Windows窗体应用程序。 这是一个分层应用程序,它有一个用于db处理的公共层。 我编写了一个SaveSOHeader方法来保存出现问题的销售订单标题: 它不会将SalesOrderHeader记录保存到数据库表中,也不会在外键表中生成重复记录 在保存之前,我填充了表单代码中的所有属性值。 这是我的模型课: public class SalesOrderHeader { public int Id { get; set; } public Syste

我正在开发一个带有实体框架的Windows窗体应用程序。 这是一个分层应用程序,它有一个用于db处理的公共层。 我编写了一个
SaveSOHeader
方法来保存出现问题的销售订单标题:

它不会将
SalesOrderHeader
记录保存到数据库表中,也不会在外键表中生成重复记录

在保存之前,我填充了表单代码中的所有属性值。 这是我的模型课:

public class SalesOrderHeader
{
    public int Id { get; set; }
    public System.DateTime OrderDate { get; set; }
    public virtual Customer Customer { get; set; }
    public virtual SalesPerson SalesPerson { get; set; }
    // Other properties stripped to keep it simple
}
public class Customer
{
    public int Id { get; set; }
    public string CustName { get; set; }
    public virtual ICollection<SalesOrderHeader> SalesOrderHeaders { get; set; }
    // Other properties stripped to keep it simple
}
public class SalesPerson
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<SalesOrderHeader> SalesOrderHeaders { get; set; }
    // Other properties stripped to keep it simple
}
问题是:

当我使用
Attach
方法以及将其更改为
db.salesforderheaders.Add(SO)时,以下代码不保存salesforderheader记录,记录以副本保存到customer、sales person表等,因此看起来db.SalesOrderHeaders.Add是无效的解决方案

我需要一些专家建议来解决这个问题

public void SaveSOHeader(SalesOrderHeader SO)
{
    try
    {
        using (SODBContext db = new SODBContext())
        {
            db.SalesOrderHeaders.Attach(SO); // → Doesn't save 
            //db.SalesOrderHeaders.Add(SO);  // → Saves but duplicates foreign key entities 
            db.SaveChanges();
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

您正在使用不同的上下文加载和保存数据,这意味着您正在断开连接的模式下工作

在断开连接模式下,实体未被上下文跟踪,当您尝试保存它们时,您需要通过使用方法和属性自己设置状态,或正确使用新实体的
添加
和现有实体的
附加
组合,来告知上下文其跟踪状态

以下是您案例中的问题:

  • 如果使用
    Attach(model)
    则表示模型未修改,因此预计不会保存它

  • 在使用
    Add(model)
    的情况下,由于模型及其所有相关模型都被视为新的,因此上下文会将它们全部保存到数据库中,从而在数据库中为外键生成类似的记录(具有不同的id)

防止插入重复的相关实体

对于外键,通常不需要设置整个导航属性,只需设置外键属性即可:

//using System.Data.Entity;
var product = new Product();
product.CategoryId = 1;
product.Name = "Product 1000";
product.Price = 1000;
product.Description = "Product 1000 Description";
using (var db = new TestDBEntities())
{
    db.Entry(product).State = EntityState.Added;
    db.SaveChanges();
}
但是,如果出于任何原因希望使用导航属性,则需要将其设置为未修改:

//using System.Data.Entity;
var product = new Product();
product.Category = new Category() { Id = 1, Name = "Category 1" };
product.Name = "Product 1000";
product.Price = 1000;
product.Description = "Product 1000 Description";
using (var db = new TestDBEntities())
{
    db.Entry(product.Category).State = EntityState.Unchanged;
    db.Entry(product).State = EntityState.Added;
    db.SaveChanges();
}
进一步阅读

要了解更多有关该问题的信息,您可以查看以下文章:


由于上下文的新实例没有跟踪更改,您需要让更改跟踪器知道实体的状态,例如
db.Entry(实体).State=EntityState.Modified
@RezaAghaei在添加您提到的代码时出现错误,原因是“object”不包含“State”的定义,并且找不到接受“object”类型的第一个参数的可访问扩展方法“State”(是否缺少using指令或程序集引用?)@Sanjeewa,因为您正在更新一个无法使用“附加”的对象<代码>附加将导致不变的EntityState
要了解附加和添加之间的区别,请签出此答案。。。从模型中剥离不必要的代码以使其更简单。您可以在中找到整个代码。仍然存在“object”问题的“State”不包含“State”的定义,并且在添加
db.Entry(product.State=EntityState.Added时,没有可访问的扩展方法“State”接受类型为“object”的第一个参数该代码已使用EF 6进行测试。我不确定你在代码中犯了什么错误。只需确保您已经使用System.Data.Entity添加了
,并且确保没有错误地创建任何
条目
扩展方法或其他内容。我在答案中的内容是从一个工作代码中复制的。我想这应该是一个简单的错误。我无意中添加了
内部对象条目(object salesOrderHeaders){throw new NotImplementedException();}
,这就是为什么添加了一些链接以进一步阅读断开连接模式和状态管理的原因。
//using System.Data.Entity;
var product = new Product();
product.Category = new Category() { Id = 1, Name = "Category 1" };
product.Name = "Product 1000";
product.Price = 1000;
product.Description = "Product 1000 Description";
using (var db = new TestDBEntities())
{
    db.Entry(product.Category).State = EntityState.Unchanged;
    db.Entry(product).State = EntityState.Added;
    db.SaveChanges();
}