I'm trying to update a field in a table just after I have added a row in a different table. (The value is just to show that the row has been imported) I thought I was using the right code here, but the bool 'Imported' field isn't updated. Here is the relevant code:
using (DbContext db = new DbContext())
{
db.Details.Add(details);
db.SaveChanges();
newID = details.DetailsID;
AccessRepository rep = new AccessRepository();
AccessDetails detailUpdate = rep.GetByID(item.AccessDetailsTableID);
detailUpdate.Imported = true;
db.SaveChanges();
}
The first SaveChanges call works, as I'm trying to add a new row, but not the second one. It successfully retrieves the data back from the repository but just doesn't update the value.
Any ideas why it might not be working?
Thanks
I think this is because your AccessRepository is using a different data context (db) to the one in scope (in your posted code)
You could try having a SaveChanges method in your AccessRepository which does the same but on the correct data context.
However, the issue with calling two saves is that you loss the single transaction benefits. So if those two updates are to be related you really should only call the SaveChanges once.
I would create an Add method and a Save method in your AccessRepository and then use something like this...
AccessRepository rep = new AccessRepository();
rep.Add(details);
AccessDetails detailUpdate = rep.GetByID(item.AccessDetailsTableID);
detailUpdate.Imported = true;
rep.Save();//this calls SaveChanges on a single data context
hope that helps
Should you use newId in GetById() method?
using (DbContext db = new DbContext())
{
db.Details.Add(details);
db.SaveChanges();
newID = details.DetailsID;
AccessRepository rep = new AccessRepository();
AccessDetails detailUpdate = rep.GetByID(newID);
detailUpdate.Imported = true;
db.SaveChanges();
}
Related
I am trying to execute below query
using (var dbcontext = new EVEntities())
{
var data_header = dbcontext.Cl.Where(x => x.PKey ==
header_key).FirstOrDefault();
if (data_header != null)
{
data_header.EstimatedCost = Math.Round(estimated_cost,2);
data_header.ClaimedCost = Math.Round(claimed_cost,2);
dbcontext.Entry<Cl>(data_header).State = System.Data.Entity.EntityState.Modified;
dbcontext.SaveChanges();
Writelog("Updated");
}
}
Here Writelog write in a text file and it is working always. But the field in Cl is not getting updated. In between the data is getting updated also.
Connection String
<connectionStrings><add name="EVEntities" connectionString="metadata=res://*/xxx_Entity_Model.csdl|res://*/xxx_Entity_Model.ssdl|res://*/xxx_Entity_Model.msl; provider=System.Data.SqlClient;provider connection string="data source=xxxxxx;initial catalog=xxxxx;persist security info=True;user id=xx;password=xxxxx;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient"/></connectionStrings>
Edit1
tried raw update also
dbcontext.Database.ExecuteSqlCommand(#"UPDATE dbo.Claims
SET EstimatedCost = #e_cost, ClaimedCost = #c_cost WHERE Pkey =
#p_key",
new SqlParameter("e_cost", Math.Round(estimated_cost, 2)),
new SqlParameter("c_cost", Math.Round(claimed_cost, 2)),
new SqlParameter("p_key", claim_header_key));
same outcome. It get updated in between. No error.
You didn't give us enough information to give you the solution. Therefore I give you a method to debug the problem.
Does the DbContext think that anything must be saved?
What SQL is sent to the database?
When you call SaveChanges, DbContext checks its ChangeTracker to see if anything must be updated. Consider to write some Debug code to detect whether there are changes.
Insert just before SaveChanges:
bool changesDetected = dbContext.ChangeTracker.HasChanges;
It might be that you need to call DetectChanges() first. I'm not sure.
If there are Changes, check if the item that you think that should be updated is changed:
IEnumerable <DbEntityEntry<Cl>> entries = dbContext.ChangeTracker.Entries<Cl>;
// We're expecting exactly one entry:
DbEntityEntry<Cl> myEntry = entries.SingleOrDefault();
Assert(myEntry != null);
If null, try to find out why it is not tracked. Was it tracked after you fetched it, before you changed it? Do you have somewhere tracking switched off? Write some other debug code where you fetch some other data. Is that tracked?
If not null, then apparently your Cl is tracked. It ought to be changed:
Assert(myEntry.State == EntityState.Modified);
If not modified, fetch the original values and the current values:
DbPropertyValues originalValues = myEntry.OriginalValues;
DbPropertyValues currentValues = myEntry.currentValues;
In your debugger, check them, or write some debug code to compare the original value with the current values. Are the changed values correct?
I'm not sure if entity framework will try to update objects that are unmodified and of which the original values are not equal to the current values. We'll find out to see what SQL is created when you do the SaveChanges.
It would be nice if your database can log all communications.
You can also log what entity framework sends to your database. For this, use property DbContext.Database.Log. For example:
dbContext.Database.Log = Console.Write;
dbContext.SaveChanges();
If you can't write to Console, write a method:
private List<string> SqlCommands {get;} = new List<string>();
void LogSqlCommands(string sqlCommand)
{
this.SqlCommands.Add(sqlCommand);
}
And in your method that following debug code:
using (var dbcontext = new EVEntities())
{
this.SqlCommands.Clear();
dbContext.Database.Log = this.LogSqlCommands;
var data_header = ... etc
dbContext.SaveChanges();
}
Put a breakpoint after SaveChanges and check the generated SQL.
Hope these debugging tips help you to find the cause of your problem
I have several tables in the DB and I want to remove all the data and repopulate the tables and only then perform a save changes (because in case the save fails I want to return to the old data).
when I remove the data from the DB and then try to add the data into the DB it fails and says "Adding a relationship with an entity which is in the Deleted state is not allowed.", but when I remove the data then save and then add the new data and saves again, everything works fine..
here is my code if it helps understanding the problem
// create the new data
SomeDataHolder data = ... ;
// save some data to re-enter back after changes
List<User> usersSave = ctx.Users.ToList();
List<UserPreferences> userPrefsSave = ctx.UserPreferences.ToList();
//clear DB
ctx.UserCourses.RemoveRange(ctx.UserCourses);
ctx.Users.RemoveRange(ctx.Users);
ctx.Specializtions.RemoveRange(ctx.Specializtions);
ctx.Course_Predecessor.RemoveRange(ctx.Course_Predecessor);
ctx.Courses.RemoveRange(ctx.Courses);
ctx.Departments.RemoveRange(ctx.Departments);
ctx.GroupsDetails.RemoveRange(ctx.GroupsDetails);
ctx.LinkTable.RemoveRange(ctx.LinkTable);
this next line makes everything works, without this line the code will fail on next save
// ctx.SaveChanges();
updateDepartmentsCoursesSpecialization(ctx, data.Specializations);
updateCoursePredecessorsAndParallel(ctx, data.Predecessors);
updateGroupDetails(ctx, data.GroupDetails);
updateLectureToPractice(ctx, data.LinkLectureWithPractice);
ctx.Users.AddRange(usersSave);
ctx.UserPreferences.AddRange(userPrefsSave);
ctx.SaveChanges();
Here you have to use Transaction.B'cos you're doing more than one atomic operation on your code base.By using Transaction where you can Combine several operations into one transaction within the same context.If there is any failure within the transaction then all will be roll-backed.
Transaction code snippet is like this :
using (var ctx = new MyContext())
{
using (var dbContextTransaction = ctx.Database.BeginTransaction())
{
try
{
//1st operations here
ctx.GroupsDetails.RemoveRange(ctx.GroupsDetails);
ctx.LinkTable.RemoveRange(ctx.LinkTable);
ctx.SaveChanges();
//2nd operations here
ctx.Users.AddRange(usersSave);
ctx.UserPreferences.AddRange(userPrefsSave);
ctx.SaveChanges();
dbContextTransaction.Commit();
}
catch (Exception)
{
dbContextTransaction.Rollback();
}
}
}
You can refer this for more info : Working with Transactions
When I try to update my entry in update function it's execute successfully but database not updated.
Please find the following code
public static string UpdateEmployee(Employee employee)
{
using (var db = new RandDEntities())
{
var empObj = db.Employees.First(x => x.EmpID == employee.EmpID);
db.Entry(empObj).State = EntityState.Modified;
db.SaveChanges();
}
return "";
}
The problem is that you're saving the wrong entity (i.e. empObj) instead of the entity that has the changes (i.e. employee). Your code pulls empObj out of the database, and then turns around and saves it, without making any changes to it. You need to modify your code as follows:
public static string UpdateEmployee(Employee employee)
{
using (var db = new RandDEntities())
{
db.Employees.Attach(employee);
db.Entry(employee).State = EntityState.Modified;
db.SaveChanges();
}
return "";
}
That has absolutely nothing to do with Entity Framework but more with the fact that you likely use localdb and your database is not where you think it is, and reinitialized (reset) to empty every time you press start.
This question, in dozens of variants, gets asked over and overy by people not bothering to check where they look (and then realizing the database files have different paths).
My Database is set up with an Entity table, which has a Ref_Type navigation property (and a FK which references TypeID). The Type table, has a Ref_Department, same FK setup. Finally, the Department table has a Ref_Locale and same FK setup.
I save the Entities in a List, which is a property of a singleton. It is created as follows;
private Singleton()
{
using (Database db = new Database())
{
List<Entities> EntityList = db.Entities.ToList<Entities>();
}
}
This is fine, the navigation properties are ALL loaded and I can access any one of them.
The problem comes when I update an Entity entry as follows;
public void UpdateEntity(Entities oldEnt, Entities newEnt)
{
using (Database db = new Database())
{
Entities ent = db.Entities.Where(e => e.EntityName == oldEnt.EntityName).FirstOrDefault();
ent.EntityName = newEnt.EntityName;
ent.EntityEmail = newEnt.EntityEmail;
...
ent.EntityType_ID = newEnt.EntityType_ID;
db.SaveChanges();
}
RefreshEntities();
}
public void RefreshEntities()
{
using (Database db = new Database())
{
db.Configuration.LazyLoadingEnabled = false;
db.SaveChanges();
EntityList = db.Entities.Include("Ref_EntityType").Include("Ref_EntityPosition").ToList<Entities>();
}
}
Ref_Entity gets loaded properly, but then within Ref_Entity, Ref_Department is just null. I've tried just using db.Entities.ToList<Entities>(); like in my constructor, no dice. As you can see, I've also tried turning LazyLoading off (I thought I might need to call SaveChanges() for it to actually apply the flag). I've also tried .Include("Ref_Department") but it just complains that it doesn't exist for Entities, which makes sense.
The newEnt that I pass to the UpdateEntity method does not have Ref_Type initialised, I'm working under the assumption that anything not changed in the UpdateEntity method would just stay the same...
So now I'm at a bit of a loss as to what's going on and how to fix it. If anyone could help explain where I'm going wrong or give me some pointers about how to fix my code to make it work, that would be great.
On a whim, I modified RefreshEntities() to;
EntityList = db.Entities.Include("Ref_EntityPosition").Include("Ref_EntityType").
Include("Ref_EntityType.Ref_Department").
Include("Ref_EntityType.Ref_Department.Ref_Locale").ToList<Entities>();
And now I'm getting all the references.
I'm still not sure why it would load all the references in the constructor but not in the RefreshEntities() method, even if the calls are identical, but this solves the problem so I'm happy enough to leave it like that.
i'm trying to execute an EF update in the following manner but continue to receive this error:
The EntityKey property can only be set when the current value of the property is null.
using (hydraEntities db = new hydraEntities())
{
YouUser = db.youusers.Include("address").Include("entity").Include("youusercontacts.contact").Include("youuserlogins").Include("youusernotes.note").Include("youusernotes.youuser.entity").Where( yu => yu.YOUUserId.Equals(YOUUserId)).First();
}
YouUser.entity.FirstName = txtFirstName.Text;
YouUser.entity.LastName = txtLastName.Text;
YouUser.address.AddressLine1 = txtAddressLine1.Text;
YouUser.address.AddressLine2 = txtAddressLine2.Text;
YouUser.address.City = txtCity.Text;
YouUser.address.State = ddlState.SelectedValue;
YouUser.address.Zipcode = txtZipcode.Text;
using (hydraEntities db = new hydraEntities())
{
db.youusers.AddObject(YouUser);
db.ObjectStateManager.ChangeObjectState(YouUser, System.Data.EntityState.Modified);
db.SaveChanges();
}
Would greatly appreciate any insight on how I can fix this and execute the statement above.
Don't use AddObject in this scenario. It is for inserting a new entity but you are updating existing one. Use Attach instead:
using (hydraEntities db = new hydraEntities())
{
db.youusers.Attach(YouUser);
db.ObjectStateManager.ChangeObjectState(YouUser, System.Data.EntityState.Modified);
db.SaveChanges();
}
In my scenario I was adding objects several times at once through different threads. I had to lock the Model Container object when doing this, to make sure only one object would be processed at once.