当前位置: 首页 > 知识库问答 >
问题:

实体框架,更新相关对象的问题

全昊焜
2023-03-14

我目前正在使用最新版本的实体框架进行一个项目,我遇到了一个似乎无法解决的问题。

当涉及到更新现有对象时,我可以很容易地更新对象属性,直到涉及到引用另一个类的属性为止。

在下面的示例中,我有一个名为Foo的类,它存储各种属性,其中2个是其他类的实例

public class Foo
{
     public int Id {get; set;}
     public string Name {get; set;}
     public SubFoo SubFoo {get; set}
     public AnotherSubFoo AnotherSubFoo {get; set}
}

当我使用下面的Edit()方法时,我传入了我想要更新的对象,并且我可以设法使名称正确更新,但是我还没有找到一种方法来更改子对象的属性。例如,如果子对象的属性为Name,并且该属性已更改,并且在my DB和newFoo之间有所不同,则不会对其进行更新。

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
        .Include(x => x.SubFoo)
        .Include(x => x.AnotherSubFoo)
        .Single(c => c.Id == newFoo.Id);

    var entry = context.Entry<Foo>(dbFoo);
    entry.OriginalValues.SetValues(dbFoo);
    entry.CurrentValues.SetValues(newFoo);

    context.SaveChanges();

    return newFoo;
}

任何帮助或指点将不胜感激。

更新:根据Slauma的评论,我修改了我的方法

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
        .Include(x => x.SubFoo)
        .Include(x => x.AnotherSubFoo)
        .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);

    context.SaveChanges();

    return newFoo;
}

现在运行此操作时,我得到错误:

实体类型Collection'1不是当前上下文模型的一部分。

为了解决这个问题,我添加了一些代码,试图将newFoo子类附加到上下文中,但这是由于一个错误,即ObjectManager已经有了一个相同的实体:

ObjectStateManager中已经存在具有相同密钥的对象。ObjectStateManager无法跟踪具有相同密钥的多个对象

共有3个答案

申阳伯
2023-03-14

也可以单独调用这些表

MyContext db = new MyContext
// I like using asynchronous calls in my API methods 
var OldFoo = await db.Foo.FindAsync(id);
var OldAssociateFoo = db.AssociatedFoo;  
var NewFoo = OldFoo;
var NewAssociatedFoo = OldAssociatedFoo;

NewFoo.SomeValue = "The Value";
NewAssociatedFoo.OtherValue = 20;

db.Entry(OldFoo).CurrentValues.SetValues(NewFoo);
db.Entry(OldAssociatedFoo).CurrentValues.SetValues(NewAssociatedFoo);

await db.SaveChangesAsync();
潘修为
2023-03-14

我想我会发布下面的链接,因为它真的帮助我了解了如何更新相关实体。

asp net mvc应用程序中使用实体框架更新相关数据

注意:我确实稍微更改了UpdateInstructorCourses函数中显示的逻辑,以满足我的需要。

司马庆
2023-03-14

货币值。设置值只更新标量属性,但不更新相关实体,因此您必须对每个相关实体执行相同的操作:

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
    context.Entry(dbFoo.AnotherSubFoo).CurrentValues.SetValues(newFoo.AnotherSubFoo);

    context.SaveChanges();

    return newFoo;
}

如果可以完全删除关系或创建关系,则还需要明确处理这些情况:

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    if (dbFoo.SubFoo != null)
    {
        if (newFoo.SubFoo != null)
        {
            if (dbFoo.SubFoo.Id == newFoo.SubFoo.Id)
                // no relationship change, only scalar prop.
                context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
            else
            {
                // Relationship change
                // Attach assumes that newFoo.SubFoo is an existing entity
                context.SubFoos.Attach(newFoo.SubFoo);
                dbFoo.SubFoo = newFoo.SubFoo;
            }
        }
        else // relationship has been removed
            dbFoo.SubFoo = null;
    }
    else
    {
        if (newFoo.SubFoo != null) // relationship has been added
        {
            // Attach assumes that newFoo.SubFoo is an existing entity
            context.SubFoos.Attach(newFoo.SubFoo);
            dbFoo.SubFoo = newFoo.SubFoo;
        }
        // else -> old and new SubFoo is null -> nothing to do
    }

    // the same logic for AnotherSubFoo ...

    context.SaveChanges();

    return newFoo;
}

如果关系已更改,并且标量属性也已更改,则最终还需要将附加实体的状态设置为“已修改”。

编辑

如果-根据您的评论-Foo。Subfo实际上是一个集合,而不仅仅是一个引用。要更新相关实体,您需要这样的内容:

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    // Update foo (works only for scalar properties)
    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);

    // Delete subFoos from database that are not in the newFoo.SubFoo collection
    foreach (var dbSubFoo in dbFoo.SubFoo.ToList())
        if (!newFoo.SubFoo.Any(s => s.Id == dbSubFoo.Id))
            context.SubFoos.Remove(dbSubFoo);

    foreach (var newSubFoo in newFoo.SubFoo)
    {
        var dbSubFoo = dbFoo.SubFoo.SingleOrDefault(s => s.Id == newSubFoo.Id);
        if (dbSubFoo != null)
            // Update subFoos that are in the newFoo.SubFoo collection
            context.Entry(dbSubFoo).CurrentValues.SetValues(newSubFoo);
        else
            // Insert subFoos into the database that are not
            // in the dbFoo.subFoo collection
            dbFoo.SubFoo.Add(newSubFoo);
    }

    // and the same for AnotherSubFoo...

    db.SaveChanges();

    return newFoo;
}

 类似资料:
  • 问题内容: 我想知道人们对通过LINQ-to-SQL支持实体框架的决定有何想法?我有一个我最初使用LINQ-to- SQL开发的应用程序。我发现它是我们应用的理想解决方案。 在尝试移植到Entity Framework时,我感到很惊讶。恕我直言,甚至还没有准备好黄金时间。没有延迟加载,没有POCO,对继承的可怕依赖。我发现它在我的情况下基本上不可用,而是决定坚持使用LINQ- to-SQL,直到以

  • 我有一个带有“Status”布尔值的付款模型,该布尔值默认为false。付款后,我需要将特定付款的“状态”更新为true。 这是我一直试图用来更改特定数据库条目的代码,但它并没有改变它。我做错了什么? 谢谢 这就是最终起作用的原因:

  • 问题内容: 似乎无法使用WCF的本机DataContractJsonSerializer或ASP.NET的本机JavaScript序列化器将Entity Framework对象序列化为JSON。这是由于两个串行器都拒绝的引用计数问题。我还尝试了Json.NET,它在引用计数问题上也特别失败。 编辑: Json.NET现在可以序列化和反序列化Entity Framework实体 。 我的对象是Ent

  • 问题内容: 像其他几个人一样,我在序列化Entity Framework对象时遇到问题,因此我可以通过JSON格式的AJAX发送数据。 我有以下服务器端方法,我正在尝试通过jQuery使用AJAX进行调用 通过AJAX调用会导致此错误: 这是因为实体框架创建循环引用以保持所有对象相关并且可访问服务器端的方式。 我从(http://hellowebapps.com/2010-09-26/produc

  • 也许问题的标题写得不好,但我不明白我还能写些什么。 我想了解,为什么下面两个案例中的第一个能起作用,以及在总体实现相同的情况下,如何让第二个也能起作用。 从代码的角度来看,什么样的原则使第一个按原样工作,也就是说,扩大了可以使用的变量的范围,所以我可以了解更多。 我想访问onclick侦听器中的'obj'变量。 案例1 案例2 我的onclicklistener只接受带有onClick方法的接口,

  • 问题内容: 我有两个表: 通常,我会创建一个映射表’ ‘来将这些表链接成多对多关系。 这是最好的方法吗?我应该将s的列表存储在xml列中,而不是存储在“事件”表中吗? 我使用带有Linq的.NET 3.5 / 4作为DAL(尽管我认为这可能与所提出的设计问题无关)。 有兴趣看看人们的意见是什么。 谢谢。戴夫 问题答案: 映射表绝对是执行此操作的最佳方法-实体框架会将映射表转换为两侧的实体集合,并且