在DB上下文中,复杂对象的更新失败

时间:2015-04-28 08:58:28

标签: c# entity-framework

我想只更新对象MwbePaymentMethod的简单属性,没有复杂属性(最后4个属性很复杂),因此它将这4个复杂属性更改为不变。但是方法编辑失败了:

  Context.Entry(payment.BillingAddress).State = EntityState.Unchanged;

有错误:

附加“MobileWallet.Common.Repository.MwbeAddress”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图表,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

模型对象:

 public class MwbePaymentMethod : BaseEntity
    {
        public enum MethodTypeEnum
        {
            Creditcard,
            Virtualcard,
            Wallet
        };
        public MethodTypeEnum MethodType { get; set; }
        public string Number { get; set; }
        public DateTime? ExpirationDate { get; set; }
        public double Balance { get; set; }
        public bool IsPending { get; set; }
        public bool IsDefault { get; set; }
        public MwbeAddress BillingAddress { get; set; }
        public MwbeCurrency Currency { get; set; }
        public MwbeUserData UserData { get; set; }
        public DateTime? PaymentDate { get; set; }

        [JsonIgnore]
        public virtual ICollection<MwbePayment> Payments { get; set; }
    }

编辑方法:

public override void Edit(MwbePaymentMethod payment)
        {

            if (payment.Currency != null && payment.Currency.Id != 0)
            {
                Context.Entry(payment.Currency).State = EntityState.Unchanged;
            }
            if (payment.UserData != null && payment.UserData.Id != 0)
            {
                Context.Entry(payment.UserData).State = EntityState.Unchanged;
            }

            if (payment.BillingAddress != null && payment.BillingAddress.Id != 0)
            {
                Debugger.Break(); 
                Context.Entry(payment.BillingAddress).State = EntityState.Unchanged;
            }

            Context.Entry(payment).State = EntityState.Modified;
            if (Context.Entry(payment).State == EntityState.Detached)
            {
                DbSet.Attach(payment);
            }
        }

ADDED1:

我稍微更改了代码,我正在读取所有导航字段/对象,特别是对于帐单地址而言,该地址未完全填充与数据库中相同的数据。

 public void UpdateMwbePaymentMethod(MwbePaymentMethodFilter filter, MwbePaymentMethodDtoInOut mwbepaymentmethod)
        {
            var currentPaymentMethod = paymentMethodRepository.FindBy(x => x.UserData.Id == filter.userId && x.Id == filter.id);
            if (currentPaymentMethod == null || currentPaymentMethod.Count() != 1)
            {
                throw new DBConcurrencyException();
            }
            var mwbePaymentPethod = Mapper.Map<MwbePaymentMethod>(mwbepaymentmethod);

            //load existing user data
            mwbePaymentPethod.UserData = userRepository.Get(filter.userId).Data;

            //load existing address with subproperties
            mwbePaymentPethod.BillingAddress = addressRepository.FindBy(x => x.Id == mwbePaymentPethod.BillingAddress.Id, x=>x.Merchants, x=>x.PaymentMethods, x=>x.Deliveries, x=>x.UserDatas).SingleOrDefault();

            if (mwbePaymentPethod.BillingAddress == null)
            {
                throw new DBConcurrencyException();
            }

            paymentMethodRepository.Edit(mwbePaymentPethod);
            paymentMethodRepository.SaveChanges();
        }

编辑方法:

public override void Edit(MwbePaymentMethod payment)
    {

        if (payment.Currency != null && payment.Currency.Id != 0)
        {
            Context.Entry(payment.Currency).State = EntityState.Unchanged;
        }
        if (payment.UserData != null && payment.UserData.Id != 0)
        {
            Context.Entry(payment.UserData).State = EntityState.Unchanged;
        }

        if (payment.BillingAddress != null && payment.BillingAddress.Id != 0)
        {
            Debugger.Break(); // tutaj byl ostatnio problem
            Context.Entry(payment.BillingAddress).State = EntityState.Unchanged;
        }
        Context.Entry(payment).State = EntityState.Modified;

    }

无论是否

1)Context.Entry(payment.BillingAddress).State = EntityState.Unchanged;

2)Context.Entry(payment.BillingAddress).State = EntityState.Modified;

仍然显示相同的错误。对我来说,如果我没有从db附加所有属性,那么应该可以工作,但它不起作用。

2 个答案:

答案 0 :(得分:0)

复杂类型不是实体,因此不会跟踪它们。他们所属的实体是。

要理解为什么这样做是有道理的: 您的MwbePaymentMethod有一个复杂类型的地址。在数据库中,它们将存储在一个表中,(默认)列名称将为: Number,MwbeAddress_Line1,MwbeAddress_Line2,MwbeAddress_PostalCode,...

如果更改地址的Line1,则需要更新数据库中的整个MwbePaymentMethod表的行。实际上,如果您更改属于实体MwbePaymentMethod的任何复杂属性的任何值,这将导致对整个实体的更新(因为它们最终都属于数据库中的同一个表)。

这就是为什么只更新对象MwbePaymentMethod的简单属性没有意义,没有[更新]复杂属性&#34;

您只能更改上下文中DbSets中实体的状态(Context.Entry(Entity).State = ...)(即Context类中DbSet中的所有X)

this。特别是名为“复杂类型:跨多个类型拆分表”的部分

答案 1 :(得分:0)

在编辑代码的第一行,将实体附加到上下文:

DbSet.Attach(payment);

注意: DbSet没有静态Attach方法。它应该是您在上下文中定义的DbSet<MwbePaymentMethod >属性。

完成后,请将付款状态设置为已修改:

Context.Entry(payment).State = EntityState.Modified;

然后设置所有其他实体的状态。考虑到,当您将树附加到上下文时,它将以未更改的状态附加。来自MSDN附加文档:

  

Attach用于使用已知存在于数据库中的实体重新填充上下文。因此,SaveChanges不会尝试将附加实体插入数据库,因为假定它已经存在。请注意,已处于某个其他状态的上下文中的实体的状态将设置为“未更改”。如果实体已处于Unchanged状态的上下文中,则Attach是无操作。

因此,您必须附加到上下文,然后在必要时将状态更改为其他内容。你正在做相反的事情。

最后验证payment对象是否具有正确的ID。如果不存在,则必须将其包含在隐藏字段或任何其他表单输入中,以便将其发回服务器。