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

P.K*_*.K. 11 c# entity-framework

我的应用程序有2个类:PaymentMethod&Currency(Currency属性PaymentMethod).当我的应用程序更新了PaymentMethod具有新值的Currency属性(值已经存在于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;
Run Code Online (Sandbox Code Playgroud)

PaymentMethodCurrency班级:

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; }
    }
Run Code Online (Sandbox Code Playgroud)

编辑方法:

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;
        }
Run Code Online (Sandbox Code Playgroud)

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);
        } 
Run Code Online (Sandbox Code Playgroud)

Autofac定义的DB上下文:

builder.RegisterType<MobileWalletContext>().As<IMwbeDbContext>().InstancePerRequest();
Run Code Online (Sandbox Code Playgroud)

更新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
Run Code Online (Sandbox Code Playgroud)

为什么没有Currency财产更新?

Ger*_*old 9

设置实体的状态(除了Added)仅影响实体的标量属性,而不影响其导航属性及其关联.

所以你有三个选择:

选项1

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

Context.Entry(entityToUpdate).State = EntityState.Modified;
Context.Entry(entityToUpdate.Currency).State = EntityState.Unchanged;
Run Code Online (Sandbox Code Playgroud)

现在EF知道Currency分配的内容PaymentMethod,因此它知道关联已更改,并且它将更新数据库中的外键.

但我不认为这对你有用.从您的问题陈述我理解currencyRepo并且paymentMethodRepository不共享相同的上下文,否则您不会首先遇到问题(货币已经附加).您不能将实体附加到两个上下文,因此要么currencyRepo在该点处置上下文,要么首先从中分离货币.非常费力.

选项2

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

选项3

不要设置Currency属性,而是添加原始外键属性,PaymentMethod.CurrencyId并在货币更改时修改该属性.这是一个标量属性,因此它将响应设置EntityState.Modified.


pqu*_*est 5

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;
        }
Run Code Online (Sandbox Code Playgroud)