8

I have a Payment model with a 'Status' boolean value which defaults to false. Once payment has been made, I need to update that specific payment's 'Status' to true.

Here's the code I've been trying to use to change the specific database entry, but it's just not changing it. What am I doing wrong?

Payment payment = new Payment();
payment = db.Payments.Find(orderId);
db.Entry(payment).State = EntityState.Modified;
payment.Status = true;
db.SaveChanges();

Thanks!

This is what ended up working:

using (var con = new ApplicationDbContext())
{
    payment = con.Payments.First(x => x.Id == orderId);
    payment.Status = true;

    con.Payments.Attach(payment);
    var entry = con.Entry(payment);
    entry.Property(e => e.Status).IsModified = true;
    con.SaveChanges();
}
7
  • Is db.Payments.Find(orderId) returns you a payment? Commented Sep 9, 2014 at 19:30
  • Yes, the orderId is to identify which payment should be modified (the orderId is the same as the Payment ID that was created when the payment entry was made). Commented Sep 9, 2014 at 19:33
  • What version of entity framework are you using? Commented Sep 9, 2014 at 19:34
  • Entity Framework: v4.0.30319 Commented Sep 9, 2014 at 19:36
  • 2
    I see no reason why what you are doing here would not work. Is this really all you are doing or are you doing more than this, but have tried to simplify in order to ask your question? Please add the code for your Payment class. Commented Sep 9, 2014 at 19:55

5 Answers 5

10
Payment payment = new Payment();
payment = db.Payments.Find(orderId);
payment.Status = true;
db.Entry(payment).State = EntityState.Modified;
db.SaveChanges();
Sign up to request clarification or add additional context in comments.

2 Comments

please provide explanation
Main difference seems to be in the following 2 lines. entry.Property(e => e.status).IsModified = true; db.Entry(record).State = EntityState.Modified;
3

The reason all of these are failing is because either the Payment object is never attached to the DBContext or the orderId doesn't actually match up with the PK on the Payments table. In order for SaveChanges() to actually work, the object you're changing needs to be tracked by the DBContext, not just have its EntityState set to Modified. Also all these examples seem grossly overcomplicated.

using (var db = new DbContext())
{
    // make sure you have the right column/variable used here
    var payment = db.Payments.FirstOrDefault(x => x.Id == orderId);

    if(payment == null) throw new Exception("Invalid id: " + orderId);

    // this variable is tracked by the db context
    payment.Status = true;

    db.SaveChanges();
}

6 Comments

I've verified that the orderId is indeed the correct value for the payment Id that I want to change. I've tried your code, but it still doesn't update that entry. If I replace this code with an "add new entry to Payment" then the code works fine, so the code does execute, but no changes are made with the updating of the entry.
@Pierre Which version of Entity Framework are you using? And is this code running inside a transaction at any layer?
Entity Framework: v4.0.30319. I don't use transactions at all.
@Pierre Did you set any custom options on your DbContext?
Nope, only using public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection") { } } Which is the default that the MVC project provides
|
2

If you just have your entity id, just do like Ali Golshani said. But if you already have the entity and just want to update, you can do this way:

 public void Update(Payment payment, int orderId)
    {
        //first find the entity to update
        Payment oldEntity = DbSet.Find(orderId);

        //detach this entity from the DbSet
        Db.Entry(oldEntity).State = EntityState.Detached;

        //set the state from the entity that you just received to modified 
        Db.Entry(obj).State = EntityState.Modified;
    }

Detaching avoids the error message: "Attaching an entity failed because another entity of the same type already has the same primary key value".

I hope that it helps.

1 Comment

This pattern is very useful if you are returning a record from an HTML post into an MVC controller and want to update the values in an existing record. Make sure that you substitute the 'obj' for the record (object) that you are passing in. (in this case it would be payment)
1

Try this one:

    Payment payment;
    using (var context = new DBContext()) //replace the name of your context
    {
        payment = context.Payments.Find(orderId);
    }

    if(payment != null)
    {
       payment.Status = true;
    }

    using (var context = new DBContext()) //replace the name of your context
    {
        context.Payments.Attach(payment);
        context.Entry(payment).State = System.Data.EntityState.Modified;    
        context.SaveChanges();
    }

4 Comments

Why do you create (and dispose of) two separate DbContexts for this simple update?
The whole update can definitely be performed under the single context. I wrote it this way because i don't know whether he works with attached entities or with detached. Attached entities demand using the same context both for select an update
Still not working. Maybe the problem lies with the orderId. I'll check if the correct orderId is posted from the payment website. But the only difference between our code is the line of code with "Attach". I've never used this term, will also read up on that. Thanks for the answer, will mark it as answered as soon as I've sorted this problem out :)
I've verified that orderId is correct and I still can't get the entry to update.
1

As mentioned here:

The Find method on DbSet uses the primary key value to attempt to find an entity tracked by the context. If the entity is not found in the context then a query will be sent to the database to find the entity there. Null is returned if the entity is not found in the context or in the database.

So be sure that Payment class looks like this:

public class Payment
{
     [Key]
     public int Id {get; set;}
     public bool Status {get; set;}
}

And your Entry save logic could look like this:

Payment payment = null;
using (var ts = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(1, 0, 0, 0)))
{
    using (var context = new DBContext()) 
    {
        context.Database.Log = s => { System.Diagnostics.Debug.WriteLine(s); };
        payment = context.Payments.Find(orderId);
        if(payment != null)
        {
            payment.Status = true;
            context.Entry(payment).State = System.Data.EntityState.Modified;    
        }
        else 
        {
            context.Payments.Add(new Payment(){
                Status = true
            });
        }
        context.SaveChanges();
    }
    ts.Complete();
}

Added transaction scope to be sure that it is properly open and close, and added sql query logging to debug window.

2 Comments

It's still not changing the State of the payment. It reaches the "if" statement and not the "else", but it doesn't change the state. The OrderId is correct, but it doesn't update that Payment for some reason...
Maybe you run your code in transaction and not commiting it? Try to wrap db context in TransactionScope as in example below. And check SQL-query which generated by EF by using its logging mechanizm.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.