问题 EF:对象更新过程不会更改一个属性的值


我的申请有2个班: PaymentMethod & Currency (Currency 属于 PaymentMethod)。当我的应用程序更新 PaymentMethod 具有新的价值 Currency propery(值已经存在于db中,但它被分配给 PaymentMethod)之后 SaveCHanges 方法, Currency 财产仍然包含旧价值。 为什么?:)

这是我的应用程序替换Currency对象值的方式:

 if (String.Compare(existingPaymentMethod.Currency.Code, mwbepaymentmethod.CurrencyCode, true) !=0)
            {
                var readCurrency = currencyRepo.FindByCode(mwbepaymentmethod.CurrencyCode);

                existingPaymentMethod.Currency = readCurrency;

            }

            paymentMethodRepository.Save(ref existingPaymentMethod);
            return true;

PaymentMethod & Currency 类别:

public class PaymentMethod : BaseEntity
    {
        public enum MethodTypeEnum
        {
            Creditcard,
            Virtualcard,
            Wallet
        };
        public MethodTypeEnum MethodType { get; set; }
        public int VendorId { get; set; }
        public virtual Address BillingAddress { get; set; }
        public virtual Currency Currency { get; set; }
    }

public class Currency : BaseEntity
    {
        [JsonProperty("code")]
        [Key]
        public string Code { get; set; }

        [JsonProperty("symbol")]
        public string Symbol { get; set; }

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

        [JsonIgnore]
        public virtual ICollection<PaymentMethod> PaymentMethods { get; set; }
    }

编辑方法:

public override void Edit(MwbePaymentMethod entityToUpdate)
        {
            DbSet.Attach(entityToUpdate);
            Context.Entry(entityToUpdate).State = EntityState.Modified;

            //manual update of  properties
            //Context.Entry(entityToUpdate.BillingAddress).State = EntityState.Modified;
            //Context.Entry(entityToUpdate.Currency).State = EntityState.Unchanged;
        }

OnModelCreating 方法:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MobileWalletContext>());
           ...
            modelBuilder.Entity<MwbePaymentMethod>().HasRequired(e => e.Currency).WithMany(e => e.PaymentMethods);

            base.OnModelCreating(modelBuilder);
        } 

Autofac定义的DB上下文:

builder.RegisterType<MobileWalletContext>().As<IMwbeDbContext>().InstancePerRequest();

更新1: EF日志显示没有货币字段更新:

UPDATE [dbo].[MwbeAddress] SET [Street] = @0, [City] = @1, [ZipCode] = @2, [Country] = @3 WHERE ([Id] = @4)
-- @0: 'FFFF12' (Type = String, Size = -1)
-- @1: 'GlasgowSSSS' (Type = String, Size = -1)
-- @2: 'B33 8TH' (Type = String, Size = -1)
-- @3: 'England' (Type = String, Size = -1)
-- @4: '2' (Type = Int32)
-- Executing at 2015-07-13 07:35:48 +02:00
-- Completed in 39 ms with result: 1

UPDATE [dbo].[MwbePaymentMethod] SET [MethodType] = @0, [VendorId] = @1, [Number] = @2, [ExpirationDate] = @3, [Balance] = @4, [IsPending]
= @5, [IsDefault] = @6 WHERE ([Id] = @7)
-- @0: '1' (Type = Int32)
-- @1: '0' (Type = Int32)
-- @2: '4444 4444 4444 4450' (Type = String, Size = -1)
-- @3: '2015-10-10 00:00:00' (Type = DateTime2)
-- @4: '0' (Type = Double)
-- @5: 'True' (Type = Boolean)
-- @6: 'False' (Type = Boolean)
-- @7: '3' (Type = Int32)
-- Executing at 2015-07-13 07:35:48 +02:00
-- Completed in 7 ms with result: 1

为什么没有更新 Currency 属性?


7890
2017-07-12 23:29


起源

它进入了if条件吗? - Amirhossein Mehrvarzi
是的,它进入了if条件 - P.K.
我会在5-6小时内给出答案,仍在等待其他解释;)。谢谢 - P.K.


答案:


设置实体的状态(除了 Added)只影响实体 标量属性,而不是它的导航属性 协会

所以你有三个选择:

选项1

将货币附加到上下文。在你的 Edit 方法:

Context.Entry(entityToUpdate).State = EntityState.Modified;
Context.Entry(entityToUpdate.Currency).State = EntityState.Unchanged;

现在EF知道了 Currency 被分配给 PaymentMethod,所以它知道 协会 已更改,它将更新数据库中的外键。

但我不认为这对你有用。从你的问题陈述我理解 currencyRepo 和 paymentMethodRepository 不要共享相同的上下文,否则你不会首先遇到问题(货币已经附加)。您不能将实体附加到两个上下文,所以也是如此 currencyRepo应该在那时处理上下文,或者你应该首先从中分离货币。非常费力。

选项2

currencyRepo 和 paymentMethodRepository (以及所有相关的存储库)在一个工作单元内共享相同的上下文实例。无论如何,这是推荐的,不仅是为了解决这个问题。

选项3

不要设置 Currency 属性,但添加原始外键属性 PaymentMethod.CurrencyId 如果货币发生变化,请修改该属性。这是一个标量属性,因此它将响应设置 EntityState.Modified


9
2017-07-19 20:28



我没有实现这个,但它似乎是合理的。我会检查并通知你。 - P.K.


DbSet.Attach 不是递归的。您需要附加所有已调入的实体:

public override void Edit(MwbePaymentMethod entityToUpdate)
        {
            DbSet.Attach(entityToUpdate);
            Context.Entry(entityToUpdate).State = EntityState.Modified;

            if(entityToUpdate.BillingAddress != null)
            {
              DbSet.Attach(entityToUpdate.BillingAddress);
              Context.Entry(entityToUpdate.BillingAddress).State = EntityState.Modified;
            }

            if(entityToUpdate.Currency != null)
            {
              DbSet.Attach(entityToUpdate.Currency);
              Context.Entry(entityToUpdate.Currency).State = EntityState.Modified;
            }

            //manual update of  properties
            //Context.Entry(entityToUpdate.BillingAddress).State = EntityState.Modified;
            //Context.Entry(entityToUpdate.Currency).State = EntityState.Unchanged;
        }

5
2017-07-17 12:56



DbContext.Attach 找不到 - P.K.
@ P.K。那些应该是的oops DBSet - pquest


这个问题是因为 外键 在PaymentMethod类中未定义的关系。需要指定这样的特定列将用于更新,如果货币是新的,那么将插入,并且将针对货币代码保存相同的代码。

public class PaymentMethod : BaseEntity
{
    public enum MethodTypeEnum
    {
        Creditcard,
        Virtualcard,
        Wallet
    };
    public MethodTypeEnum MethodType { get; set; }
    public int VendorId { get; set; }
    public virtual Address BillingAddress { get; set; }

    public string CurrencyCode {get;set;} //Replace with actual column name

     [ForeignKey("CurrencyCode ")]
    public virtual Currency Currency { get; set; }

}

0
2017-07-22 14:36



定义了Currency的外键,但名称为:FK_dbo.MwbePayment_dbo.MwbeCurrency_Currency_Code。我在数据库中看到它。 - P.K.
这也需要在onmodelcreation或属性级别的类级别的代码中指定。 Onmodelcreation指定了关系,但未指定定义外键关系的指定属性(key)。请检查上面的代码如何指定外键关系。 - Rohit Harkhani