其他分享
首页 > 其他分享> > CodeGo.net>如何停止尝试更改entitykey值的dbentityentry.currentvalues.setvalues

CodeGo.net>如何停止尝试更改entitykey值的dbentityentry.currentvalues.setvalues

作者:互联网

我正在使用以下代码,使用从我的代码中收集的新信息来更新实体对象.我正在使用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值(显然,我不希望它执行此操作),因此会引发错误.

我想这里有两个问题:

>有没有办法阻止它尝试更新键值?
>如果没有,如何复制曾经在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;
    }
}

解决方法:

在我看来,该异常表明您的调用代码中有问题-或至少是异常情况.

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

实际上,设置当前值与DbContext的工作原理不同,因为必须显式提供当前连接的实体才能更新其当前值.使用ObjectContext的ApplyCurrentValues,您不提供此实体:

objectContext.ApplyCurrentValues("MyEntitySet", sourceObject);

这是不同的,因为…

> sourceObject必须是一个实体,并且不能是任意对象
>它更新具有与sourceObject相同的键值的附加实体的值

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

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

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

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

EF在这里会抱怨您尝试更改键值.而且它会抱怨sourceObject与currentObject的类型不同,而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;
}

标签:entity-framework-5,c
来源: https://codeday.me/bug/20191123/2066369.html