【问题标题】:how to stop dbentityentry.currentvalues.setvalues trying to change entitykey value如何停止 dbentityentry.currentvalues.setvalues 尝试更改实体键值
【发布时间】:2014-03-26 00:39:14
【问题描述】:

我正在使用以下代码使用从我的代码中收集的新信息更新实体对象。我正在使用 Entity Framework 5

我使用以下扩展方法(作为我在 EF4 中使用的重新附加代码的替代方法):

public static void ApplyValues(this object currentObject, object sourceObject, System.Data.Entity.DbContext obj)
{
  obj.Entry(currentObject).CurrentValues.SetValues(sourceObject);
}

问题在于,当调用此方法时,SetValues 方法会尝试修改附加对象上的EntityKey 值(显然我不希望它这样做),因此会引发错误。

我想这里有两个问题:

  1. 有没有办法阻止它尝试更新键值?

  2. 如果不是,我该如何复制过去在 EF4 中正常工作的 ObjectContext.ApplyCurrentValues() 代码?

----更新----

我之前用于EF4的代码如下:

public static System.Data.Objects.DataClasses.EntityObject ReAttach(this System.Data.Objects.ObjectContext obj, System.Data.Objects.DataClasses.EntityObject objectDetached)
{
    if (objectDetached.EntityKey != null)
    {
        object original = null;
        if (obj.TryGetObjectByKey(objectDetached.EntityKey, out original))
        {
            objectDetached = obj.ApplyCurrentValues(objectDetached.EntityKey.EntitySetName, objectDetached);
            return objectDetached;
        }
        else
        {
            throw new ObjectNotFoundException();
        }
    }
    else
    {
        return objectDetached;
    }
}

【问题讨论】:

  • 我会感兴趣的是,您使用 EF 4 和 ObjectContext 的相应代码到底是什么样子的。同样使用ObjectContext,您要么会得到相同的异常,要么会更新currentObject 以外的另一个实体(请参阅下面的答案)。我不知道像您在问题中尝试的更新程序如何与ObjectContext 一起使用。

标签: c# entity-framework-5


【解决方案1】:

在我看来,这个异常表明你的调用代码有问题——或者至少是不寻常的。

currentObject 是一个附加实体,而sourceObject(通常)是一个分离对象(不一定是实体),应该具有相同的键值(或根本没有键属性)。

确实,设置当前值与DbContext 的工作方式不同,因为您必须显式提供当前附加的实体才能更新其当前值。使用 ApplyCurrentValuesObjectContext 您不提供此实体:

objectContext.ApplyCurrentValues("MyEntitySet", sourceObject);

这是不同的,因为...

  • sourceObject 必须是实体,不能是任意的object
  • 它更新与sourceObject具有相同键值的附加实体的值

在您的示例中,它将更新除 currentObject 之外的另一个实体,因为显然 currentObject 不是与 sourceObject 具有相同键的实体。

如果您使用过ObjectStateEntry.ApplyCurrentChanges(更接近DbContext 中的新版本),您会得到同样的异常:

var objectContext = ((IObjectContextAdapter)obj).ObjectContext;

var entry = objectContext.ObjectStateManager.GetObjectStateEntry(currentObject);
entry.ApplyCurrentValues(sourceObject);

EF 会在此处抱怨您尝试更改键值。如果sourceObjectcurrentObject 的类型不同,它会抱怨,而DbContext 允许这样做(这使得DbContext 的过程在我看来更有用,因为您可以使用具有匹配属性名称的任意对象 -例如 DTO - 更新实体)。

编辑

重现您在 EF 4 中使用的方法的主要问题是具有 EF 5/DbContext 的实体不是从 EntityObject 派生的,而是 POCO。因此,您没有可用的 EntityKey 来允许此方法的通用实现。

您可以做的是引入一个标记实体关键属性的接口,例如:

public interface IEntity
{
    int Id { get; set; }
}

您的实体类将实现此接口,例如 Order 实体:

public class Order : IEntity
{
    public int Id { get; set; }
    public DateTime ShippingDate { get; set; }
    // etc.
}

你可以为这个接口创建一个带有约束的泛型方法:

public static T ReAttach<T>(DbContext context, T objectDetached)
    where T : class, IEntity
{
    T original = context.Set<T>().Find(objectDetached.Id);
    if (original == null)
        throw new ObjectNotFoundException();

    context.Entry(original).CurrentValues.SetValues(objectDetached);

    return objectDetached;
}

如果您的实体并不总是具有 int 属性 Id 但它们的键具有不同的类型、名称或可能是复合的,那么将实体的键传递到方法中而不是使用接口可能是更简单的方法:

public static T ReAttach<T>(DbContext context, T objectDetached,
    params object[] keyValues) where T : class
{
    T original = context.Set<T>().Find(keyValues);
    if (original == null)
        throw new ObjectNotFoundException();

    context.Entry(original).CurrentValues.SetValues(objectDetached);

    return objectDetached;
}

【讨论】:

  • 好的,在这种情况下,也许我的问题应该是“EF5 等效于 objectContext.ApplyCurrentValues() 是什么?”虽然这个确切的问题是导致我现在拥有的代码的原因......基本上,我不必手动显式更新每个值,我希望能够通过一个方法调用更新所有值(除了键值) .显然,这正是 ApplyCurrentValues() 让我在 EF4 中做的事情。
  • @coolblue2000:不,这不是ApplyCurrentValues 所做的。这就是“在您的示例中它将更新另一个实体而不是 currentObject”的重点,因此我在您的问题下提出了评论问题。我不清楚你的代码过去是什么样子的。
  • 好的,我现在已经用我在 Entity Framework 4 中非常成功地使用的代码更新了我的问题。我想在 EF5 中复制它。
  • 为什么调用代码会有问题?例如,如果您从没有相同键或根本没有键(例如 .csv)的外部源导入数据,并通过其他属性将其与实体匹配。你知道这是你想要的那个实体的新数据,但是你不能设置它,因为来自.csv的实体的键有默认值。
猜你喜欢
  • 2012-10-28
  • 2011-04-05
  • 2020-09-06
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多