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
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'm trying to make a simple database insert for just one table, the insert and the connections are working perfectly.The problem appears only when the exceptions arise for entering bad data.
Here is my code: (using MySql and EF6)
using (MaintenanceDB db = new MaintenanceDB())
{
try
{
employee employee = new employee
{
ID = idTBA.textBox.Text,
EName = enTBA.textBox.Text,
AName = anTBA.textBox.Text,
CareerCode = careerCodeCBA.comboBox.SelectedItem.ToString(),
Specialization = specTBA.textBox.Text,
Mobile = mobileTBA.textBox.Text,
Telephone = teleTBA.textBox.Text,
Email = emailTBA.textBox.Text
};
db.employees.Add(employee);
db.SaveChanges();
}
catch (DbUpdateException exception)
{
MessageBox.Show(exception.InnerException.InnerException.Message);
}
catch (EntityException exception)
{
MessageBox.Show(exception.InnerException.Message);
}
}
so if the data entered correctly everything is smooth and fine, but if I entered duplicate ID for example the first time it's going to the first catch block and tell me there is a duplicate , at this point there is something wrong, it seems the connection isn't closed here (Despite using finally and dispose on db), the next time I hit the save button the error "Nested Transactions are not supported" appears, and then the db closes and I'm able to enter new data!
I tried opening the connection manually or starting a transaction and closing it manually as I found in few posts here but nothing seems to solve the problem
It seems like a mysql bug...., #71502
[27 Feb 15:54] Raif Atef
This bug is due to a bug in the MySqlTransaction class.
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).
I have developed a WCF api which is using nHibernate. I am new to this. I have used session.update to take care of transaction. I have a for loop in which based on select condition I am updating a record ie. If A is present in tabel1 then I am updating the table else inserting a new entry.
I am getting "could not execute query." when trying to execute a select query on a table which was previously being updated by adding a new entry in the table.
What I think is, because I am using session.save(table1) and then trying select entries from that table I am getting an error. Since session.save temporarily locks the table I am not able to execute a select query on that table.
What can be the solution on this?
Update:
This the for loop I am using to check in the database for some field:
using (ITransaction tranx = session.BeginTransaction())
{
savefunction();
tranx.Commit();
}
Save function:
public void savefunction()
{
for (int i = 0; i < dictionary.Count; i++)
{
ICandidateAttachmentManager candidateAttach = new ManagerFactory().GetCandidateAttachmentManager();
CandidateAttachment attach = new CandidateAttachment();
attach = checkCV();
if(attach == null)
{
//insert new entry into table attach
session.save(attach);
}
}
}
checkCV function:
public void checkCV()
{
using (ICandidateAttachmentManager CandidateAttachmentManager = new ManagerFactory().GetCandidateAttachmentManager())
{
IList<CandidateAttachment> lstCandidateAttachment = CandidateAttachmentManager.GetByfkCandidateId(CandidateId);
if (lstCandidateAttachment.Count > 0)
{
CandidateAttachment attach = lstCandidateAttachment.Where(x => x.CandidateAttachementType.Id.Equals(FileType)).FirstOrDefault();
if (attach != null)
{
return null;
}
else
{
return "some string";
}
}
}
}
What happening here is in the for loop if say for i=2 the attach value comes to null that I am entering new entry into attach table. Then for i=3 when it enters checkCV function I get an error at this line:
IList lstCandidateAttachment =
CandidateAttachmentManager.GetByfkCandidateId(CandidateId);
I think it is because since I am using session.save and then trying to read the tabel contents I am unable to execute the query and table is locked till I commit my session. Between the beginTransaction and commit, the table associated with the object is locked. How can I achieve this? Any Ideas?
Update:
I read up on some of the post. It looks like I need to set isolation level for the transaction. But even after adding it doesn't seem to work. Here is how I tried to inplement it:
using (ITransaction tranx = session.BeginTransaction(IsolationLevel.ReadUncommitted))
{
saveDocument();
}
something I don't understand in your code is where you get your nHibernate session.
Indeed you use
new ManagerFactory().GetCandidateAttachmentManager();
and
using (ICandidateAttachmentManager CandidateAttachmentManager = new ManagerFactory().GetCandidateAttachmentManager())
so your ManagerFactory class provides you the ISession ?
then you do:
CandidateAttachment attach = new CandidateAttachment();
attach = checkCV();
but
checkCV() returns either a null or a string ?
Finally you should never do
Save()
but instead
SaveOrUpdate()
Hope that helps you resolving your issue.
Feel free to give more details
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();
}