Entity wont delete from Azure Table - c#

when i try to delete the entity Visual Studio keeps crashing on the line "serviceContext.DeleteObject(entity);"and saying "The context is not currently tracking the entity." Has anyone any ideas why and how to fix it?
CloudTableQuery<ScheduleEntity> query = scheduleManNot.retrieveSchedule();
//Checks every entry
foreach (ScheduleEntity entity in query)
{
comparison = System.DateTime.Compare(entity.eventTime, time);
if (comparison <= 0)
{
changeConfirmation = scheduleManNot.changeInstanceCount(entity.subscriptionID, entity.amount, entity.serviceName);
if (changeConfirmation == false)
{
Console.WriteLine("Configuration Change failed");
}
if (changeConfirmation == true)
{
Console.WriteLine("Configuration Change Succeeded");
Console.WriteLine(entity.serviceName + " had its instance count changed to " + entity.amount);
serviceContext.AttachTo("schedule", entity, "*");
serviceContext.DeleteObject(entity);
//Submit the operation to the table service
serviceContext.SaveChangesWithRetries();

Since you are receiving the entity over a query, you do not need to attach the entity.
Thus I think here attachto is not needed at all as you have stated in the comment.
If you need to delete an unattached entity, you can first attach it and mark is as deleted.

Related

data context save changes not working in C# entity framwork

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

DbContext SaveChanges stuck on validation error, keeps throwing same validation error after changing data

I have a method to update data from a CSV with a DbContext. I deliberately uploaded some bad data so that I could test the output when there's a validation error. The data I uploaded had an invalid state, so I got the error Test.Entry#aol.com has the following validation errors:-"Field: "State", Error: "The field State must be a string or array type with a maximum length of '2'."
However, I then fixed the data, but continued to get the same error. I then tried to upload some completely different data - e.g. DifferentEntry#gmail.com - and still have the same validation error, for Test.Entry#aol.com even though I'm not creating an entry with that email address at all.
try
{
var success = _dbContext.SaveChanges() > 0;
return success ? "Done! Please reload the page" : "Failed to update entries";
}
catch (DbEntityValidationException e)
{
var output = "FAILED TO SAVE CHANGES TO DATABASE. Please see the following validation errors:<br/>";
foreach (var eve in e.EntityValidationErrors)
{
output += String.Format("{0} has the following validation errors:",
eve.Entry.Property("Email").CurrentValue);
foreach (var ve in eve.ValidationErrors)
{
output += String.Format("- Field: \"{0}\", Error: \"{1}\"<br/>",
ve.PropertyName, ve.ErrorMessage);
}
}
return output;
}
I stepped through the code and confirmed that the entry being created is correct, that all of the values are what I have in my CSV file, but then it throws the exception for the old data. Why is it still trying to save a previous entry, and how do I get rid of it?
A bit more information:
public class EntriesRepository : CachableBase, IEntriesRepository
{
private readonly IeBusinessEntities _ieBusinessEntities;
public EntriesRepository(IeBusinessEntities ieBusinessEntities)
{
_ieBusinessEntities = ieBusinessEntities;
}
public class UpdateEntries(List<Entry> entries){
foreach (var entry in entries){
_ieBusinessEntities.Entries.Add(entry);
}
[the Try/Catch from above, with var success = _ieBusinessEntities.SaveChanges() > 0;]
}
.....
eBusinessEntities inherits DbContext
I resolved it by adding a method to dispose of all changed on error, copied from https://stackoverflow.com/a/16438187/3784238. I'm still not sure why this was necessary though, would be great if anyone could answer that
public void DiscardChanges()
{
ChangeTracker.DetectChanges();
//get all entries that are changed
var entries = ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged).ToList();
//somehow try to discard changes on every entry
foreach (var dbEntityEntry in entries)
{
var entity = dbEntityEntry.Entity;
if (entity == null) continue;
if (dbEntityEntry.State == EntityState.Added)
{
//if entity is in Added state, remove it. (there will be problems with Set methods if entity is of proxy type, in that case you need entity base type
var set = Set(entity.GetType());
set.Remove(entity);
}
else if (dbEntityEntry.State == EntityState.Modified)
{
//entity is modified... you can set it to Unchanged or Reload it form Db??
dbEntityEntry.Reload();
}
}
}

You cannot perform operation Remove on an object in state Existing

I am using Visual Studio 2017 with smo dll
and trying to remove a file from database files with the following procedure
public string RemoveFile(string fileName,string databaseName)
{
Server srv = new Server(servConn);
Database database = srv.Databases[databaseName];
if (database != null)
{
var file = LoadFiles(databaseName).Where(a => a.Name == fileName);
if (!file.Any())
{
SqlServerDisconnect();
return "File Doesn't Exist.kindly Enter Right File Name";
}
else
{
DataFile fileToRemove = file.FirstOrDefault();
database.FileGroups[fileToRemove.Parent.Name].Files.Remove(fileToRemove);
database.Alter();
return "File Removed Successfully";
}
}
}
I am not going to mention the code of servConn parameter and SqlServerDisconnect in order to abbreviate code that I have used in other places and I am sure that it works well.
When I remove a file that I take it's name from one of existing files' logical names
RemoveFile("File1",MyDataBase")
I get the message:
You cannot perform operation Remove on an object in state Existing.
How can I update the state of the file before removing it even though state field is read only and is my way in removing the file right?
You are using SMO however; For alternative way, If you can execute the SQL to do these operations. I would suggest to simply use TSQLs to remove file like :
ALTER DATABASE SchoolDb2012
REMOVE FILE schoolDataFile1;
GO
You can find detailed information here https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-file-and-filegroup-options?view=sql-server-2017
i updated my procedure to drop the file directly and not from it's file group
and the exception disappeared
public string RemoveFile(string fileName,string databaseName)
{
Server srv = new Server(servConn);
Database database = srv.Databases[databaseName];
if (database != null)
{
var file = LoadFiles(databaseName).Where(a => a.Name == fileName);
if (!file.Any())
{
SqlServerDisconnect();
return "File Doesn't Exist.kindly Enter Right File Name";
}
else
{
DataFile fileToRemove = file.FirstOrDefault();
fileToRemove.Drop();
database.Alter();
return "File Removed Successfully";
}
}
}
You can use SetState change the SmoObject status
e.g.
var removeColumn = target.Columns.OfType<Column>().Where(x => !source.Columns.Contains(x.Name)).ToList();
foreach (Column columItem in removeColumn)
{
//If you want remove this item just replace Remove to SetState
columItem.SetState(SqlSmoState.ToBeDropped);
//If I use Remove will got You cannot perform operation Remove on an object in state Existing
//target.Columns.Remove(columItem.Name);
}

Nhibernate transaction locks a tabel

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

Not able to retrieve OriginalValues in Entity Framework 5

I am writing a asp.net mvc4 app and I am using entity framework 5. Each of my entities have fields like EnteredBy, EnteredOn, LastModifiedBy and LastModifiedOn.
I am trying to auto-save them by using the SavingChanges event. The code below has been put together from numerous blogs, SO answeres etc.
public partial class myEntities : DbContext
{
public myEntities()
{
var ctx = ((IObjectContextAdapter)this).ObjectContext;
ctx.SavingChanges += new EventHandler(context_SavingChanges);
}
private void context_SavingChanges(object sender, EventArgs e)
{
ChangeTracker.DetectChanges();
foreach (ObjectStateEntry entry in
((ObjectContext)sender).ObjectStateManager
.GetObjectStateEntries
(EntityState.Added | EntityState.Modified))
{
if (!entry.IsRelationship)
{
CurrentValueRecord entryValues = entry.CurrentValues;
if (entryValues.GetOrdinal("LastModifiedBy") > 0)
{
HttpContext currContext = HttpContext.Current;
string userName = "";
DateTime now = DateTime.Now;
if (currContext.User.Identity.IsAuthenticated)
{
if (currContext.Session["userId"] != null)
{
userName = (string)currContext.Session["userName"];
}
else
{
userName = currContext.User.Identity.Name;
}
}
entryValues.SetString(
entryValues.GetOrdinal("LastModifiedBy"), userName);
entryValues.SetDateTime(
entryValues.GetOrdinal("LastModifiedOn"), now);
if (entry.State == EntityState.Added)
{
entryValues.SetString(
entryValues.GetOrdinal("EnteredBy"), userName);
entryValues.SetDateTime(
entryValues.GetOrdinal("EnteredOn"), now);
}
else
{
string enteredBy =
entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"));
DateTime enteredOn =
entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn"));
entryValues.SetString(
entryValues.GetOrdinal("EnteredBy"),enteredBy);
entryValues.SetDateTime(
entryValues.GetOrdinal("EnteredOn"), enteredOn);
}
}
}
}
}
}
My problem is that entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy")) and entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn")) are not returning the original values but rather the current values which is null. I tested with other fields in the entity and they are returning the current value which were entered in the html form.
How do I get the original value here?
I think the problem may be that you are using the instance provided by the model binder as the input to your controller method, so EF does not know anything about that entity and its original state. Your code may look like this:
public Review Update(Review review)
{
_db.Entry(review).State = EntityState.Modified;
_db.SaveChanges();
return review;
}
In that case, EF knows nothing about the Review instance that is being saved. It is trusting you and setting it as modified, so it will save all of its properties to the database, but it does not know the original state\values of that entity.
Check the section named Entity States and the Attach and SaveChanges Methods of this tutorial. You can also check the first part of this article, that shows how EF does not know about the original values and will update all properties in the database.
As EF will need to know about the original properties, you may first load your entity from the database and then update its properties with the values received in the controller. Something like this:
public Review Update(Review review)
{
var reviewToSave = _db.Reviews.SingleOrDefault(r => r.Id == review.Id);
//Copy properties from entity received in controller to entity retrieved from the database
reviewToSave.Property1 = review.Property1;
reviewToSave.Property2 = review.Property2;
...
_db.SaveChanges();
return review;
}
This has the advantage that only modified properties will be send and updated in the database and that your views and view models don't need to expose every field in your business objects, only those that can be updated by the users. (Opening the door for having different classes for viewModels and models\business objects). The obvious disadvantage is that you will incur an additional hit to the database.
Another option mentioned in the tutorial I referenced above is for you to save the original values somehow (hidden fields, session, etc) and on save use the original values to attach the entity to the database context as unmodified. Then update that entity with the edited fields. However I would not recommend this approach unless you really need to avoid that additional database hit.
Hope that helps!
I was running into a similar problem when trying to audit log the Modified values of an Entity.
It turns out during the post back the ModelBinder doesn't have access to the original values so the Model received is lacking the correct information. I fixed my problem by using this function which clones the current values, relods the object, and then reset the current values.
void SetCorrectOriginalValues(DbEntityEntry Modified)
{
var values = Modified.CurrentValues.Clone();
Modified.Reload();
Modified.CurrentValues.SetValues(values);
Modified.State = EntityState.Modified;
}
You can gain access to the DbEntityEntry though the change tracker, or the entry function from your context.

Categories

Resources