Unable to loop through and delete child records - c#

I have the following action method:-
try
{
repository.DeleteServer(id, ADusername);
repository.Save();
return Json(new { IsSuccess = "True", id = id, description = tag }, JsonRequestBehavior.AllowGet);
}
which will call the following repository method to delete an object:-
public void DeleteServer(int id,string username)
{
var server = tms.TMSServers.SingleOrDefault(a=>a.TMSServerID == id);
var auditinfo = IntiateTechnologyAudit(tms.AuditActions.SingleOrDefault(a => a.Name.ToUpper() == "DELETE").ID,
server.Technology.TechnologyType.AssetTypeID,
username, server.TMSServerID);
var technology = tms.Technologies.Include(a=>a.TMSSwitchPorts).SingleOrDefault(a => a.TechnologyID == id);
technology.IsDeleted = true;
tms.Entry(technology).State = EntityState.Modified;
tms.TMSServers.Remove(server);
foreach (var switchport in technology.TMSSwitchPorts)
{
tms.TMSSwitchPorts.Remove(switchport);
}
InsertOrUpdateTechnologyAudit(auditinfo);
}
the problem i am facing is insdie the foreach where the deletion will not be performed and no exception will be raised. when i debug my code the action method will call the deleteserver methods, then when the code reach the foreach it will not iterate over the technology.TMSSwtichPort instead the code will break without errors and the .save inside my action method will not be reached ?can any one advice what might be the problem ?
Thanks

I would imagine it's because you are using a foreach over a collection that you are indirectly modifying by deleting members.
Running your foreach over a separate collection might help, because then your enumeration isn't invalidated by the delete:
var toDelete = technology.TMSSwitchPorts.ToList();
foreach (var switchport in toDelete)
{
tms.TMSSwitchPorts.Remove(switchport);
}

Related

DbSet.Remove() seems like to remove sometimes

Hello I have this project on Entity Framework for an exam, I have 157 test to pass and I pass 155, the last 2 are very similar to others but I dont understand why fails, I put some code so I can explain better:
public void GetUsers_OnDeletedObject_Throws() {
Site.Delete();
Assert.That(() => Site.GetUsers(), Throws.TypeOf<InvalidOperationException>()); }
I defined the Delete() method to recorsively call Delete to resources in the site(like users), then remove the site from the context.
From now on any method in the site must throw InvalidOperationException because the site doesn't exist anymore, but in some way Site.GetUsers() find a site and dont throw.
The real mistery is if I try to insert other methods (written in same way) between the delete and the assert the extra method throw InvalidOperationException!
Site.Delete() code:
using (var ctx = new SiteContext(connectionString))
{
var site = ctx.Sites.Find(Name);
foreach (var a in GetAuctions()) ctx.Auctions.Remove(a);
foreach (var s in GetSessions()) ctx.Sessions.Remove(s);
foreach (var u in GetUsers()) ctx.Users.Remove(u);
ctx.Sites.Remove(site);
ctx.SaveChanges();
}
Part of GetUsers where should throw
public IEnumerable<IUser>GetUsers()
{
using (var ctx = new SiteContext(connectionString))
{
var site = ctx.Sites.SingleOrDefault(s => s.Name == Name);
AlreadyDeleted(site);
AlreadyDeleted() code:
public static void AlreadyDeleted(object o)
{
if (null == o) throw new InvalidOperationException();
}

C# - how to delete row in realm - android xamarin

i tried this method that I created but it prompts me an error:
Realms.RealmInvalidObjectException:This object is detached. Was it deleted from the realm?'
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
using (var transaction = Realm.GetInstance(config).BeginWrite())
{
Realm.GetInstance(config).Remove(denom_list[0]);
transaction.Commit();
}
}
what is the proper coding for deleting records from database in realm in C# type of coding?
You are doing it the right way. The error message you are getting indicates that the object was removed already. Are you sure it still exists in the realm?
UPDATE:
I decided to update this answer because my comment on the other answer was a bit hard to read.
Your original code should work fine. However, if you want deleteFromDatabase to accept lists with CashDenomination instances that either have been removed already or perhaps were never added to the realm, you would need to add a check. Furthermore, note that you should hold on to your Realm instance and use it in the transaction you created. In most cases, you want to keep it around even longer, though there is little overhead to obtaining it via GetInstance.
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
if (!denom_list[0].IsValid) // If this object is not in the realm, do nothing.
return;
var realm = Realm.GetInstance(config);
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom_list[0]);
transaction.Commit();
}
}
Now, if you want to use identifiers, you could look it up like you do, but still just use Remove:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.All<CashDenomination>().FirstOrDefault(c => c.denom_id == denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
Finally, if your CashDenomination has denom_id marked as PrimaryKey, you could look it up like this:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.ObjectForPrimaryKey<CashDenomination>(denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
public void deleteFromDatabase(Realm realm, long cashDenominatorId)
{
realm.Write(() =>
{
var cashDenominator = realm.All<Person>().Where(c => c.Id == cashDenominatorId);
Realm.RemoveRange<CashDenomination>(((RealmResults<CashDenomination>)cashDenominator));
});
}
Which you would call as
Realm realm = Realm.GetInstance(config);
var denom_list = ...
// ...
deleteFromDatabase(realm, denom_list[0].id);
I already made it having this code :) thanks to #EpicPandaForce 's answer.
public void deleteFromDatabase(int denom_ID, int form_ID)
{
//Realm realm;
//and
//RealmConfiguration config = new RealmConfiguration(dbPath, true);
//was initialized at the top of my class
realm = Realm.GetInstance(config);
realm.Write(() =>
{
var cashflow_denom = realm.All<CashDenomination>().Where(c => c.denom_id == denom_ID);
var cashflow_form = realm.All<CashForm>().Where(c => c.form_id == form_ID);
realm.RemoveRange(((RealmResults<CashDenomination>)cashflow_denom));
realm.RemoveRange(((RealmResults<CashForm>)cashflow_form));
});
}
it is now deleting my data without exception :)

Updating Entity in EF6 gives primary key exception

When I try to update this object in EF6 I get an error stating more than 1 entity has this primary key. Looking at this DB I know this to be untrue(from what I can see).
I need to be able to update a second object based on one of the properties on the posted object. The code below produces the error. I have left in commented out pieces that I have tried to get this to work.
public async Task<ActionResult> Edit(PricingRule pricingRule)
{
if(ModelState.IsValid)
{
var currentUser = await serv.UserManager.FindByIdAsync(User.Identity.GetUserId());
var company = currentUser.Company;
//var entityRule = serv.PricingService.PricingRules.Get(pricingRule.PricingRuleId);
//If this is the first rule, set it to the company default
var rulesCount = company.PricingRules.Count;
if (rulesCount <= 1 || company.DefaultPricingRule == null)
pricingRule.DefaultPricingRule = true;
//Make sure no other rules are marked as default, and update the company with this rule as default
if (pricingRule.DefaultPricingRule)
{
if (company.DefaultPricingRule != null)
{
var oldRule = serv.PricingService.PricingRules.Get(company.DefaultPricingRule.PricingRuleId);
oldRule.DefaultPricingRule = false;
//serv.PricingService.PricingRules.Update(oldRule);
}
company.DefaultPricingRule = pricingRule;
serv.CoreService.Companies.Update(company);
}
serv.PricingService.PricingRules.Update(pricingRule);
await serv.SaveAllChangesAsync();
return RedirectToAction("Index");
}
return View(pricingRule);
}
Whether or not it is the best practice or how it should technically be done, this is how I solved my problem.
The edited object I was passing in, needed to be marked as modified first, before doing any other operations. I am assuming this is because the context could then grab it and all other operations regarding it would be done "within context". Other wise I think it was trying to add a new object if I tried to attach it to company.DefaultPricingRule.
public async Task<ActionResult> Edit(PricingRule pricingRule)
{
if(ModelState.IsValid)
{
serv.PricingService.PricingRules.Update(pricingRule);
var currentUser = await serv.UserManager.FindByIdAsync(User.Identity.GetUserId());
var company = currentUser.Company;
//If this is the first rule, set it to the company default
var rulesCount = company.PricingRules.Count;
if (rulesCount <= 1 || company.DefaultPricingRule == null)
pricingRule.DefaultPricingRule = true;
//Make sure no other rules are marked as default, and update the company with this rule as default
if (pricingRule.DefaultPricingRule)
{
if (company.DefaultPricingRule != null)
{
var oldRule = serv.PricingService.PricingRules.Get(company.DefaultPricingRule.PricingRuleId);
oldRule.DefaultPricingRule = false;
serv.PricingService.PricingRules.Update(oldRule);
}
company.DefaultPricingRule = pricingRule;
serv.CoreService.Companies.Update(company);
}
await serv.SaveAllChangesAsync();
return RedirectToAction("Index");
}
return View(pricingRule);
}
If Anyone has a comment on if this is best practice or if there is a better way to do it, I gladly take criticism.

Which one of these async calls is not like the other?

I suspect I have a deadlock issue, but it's an odd one that I can't rationalize. I have an API that needs to verify a few things in order to process the call. As part of the business logic, I might have to make more of those same calls as well. In this case, if a particular piece of data associated with an entity is not found, we attempt to use a backup (if one is configured), which requires checking other entities. Eventually, the code will hang.
Let's just dive into the code (comments highlight the calls in question).
API Controller:
public async Task<HttpResponseMessage> Get(int entityID, string content, bool? useBackUp = true)
{
//Some look-ups here, no issues at all
//This works, but it's this method that has an issue later in the process.
SystemEntity entityObj =
await BusinessLayer.GetSystemEntityAsync(SystemEntityID);
if (entityObj == null)
{
return new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.BadRequest,
Content = new StringContent("Entity is unavailable.")
};
}
string text = BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp).Result.FirstOrDefault().Value;
if (text == null)
{
return new HttpResponseMessage {StatusCode = System.Net.HttpStatusCode.NoContent};
}
return new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.OK,
Content = new StringContent(text)
};
}
Business Layer:
public async Task<Dictionary<string, string>> GetContentTextAsync(int systemEntityID, List<string> contentNames, bool useBackUp)
{
Dictionary<string, string> records = new Dictionary<string, string>();
//We iterate for caching purposes
foreach (string name in contentNames)
{
string nameCopy = name;
string record = Cache.GetData(
string.Format("{0}_{1}_{2}", CONTENT, systemEntityID, name), () =>
DataLayer.GetCotnent(systemEntityID, nameCopy));
if (record == null && useBackUp)
{
List<int> entityIDs = new List<int> {systemEntityID};
int currentEntityID = systemEntityID;
//Here's that method again. This call seems to work.
SystemEntity currentEntity = await GetSystemEntityAsync(systemEntityID);
if (currentEntity != null && currentEntity.BackUpID.HasValue)
{
currentEntityID = (int) currentEntity.BackUpID;
}
while (!entityIDs.Contains(currentEntityID))
{
int id = currentEntityID;
record = Cache.GetData(
string.Format("{0}_{1}_{2}", CONTENT, systemEntityID, name), () =>
DataLayer.GetCotnent(id, nameCopy));
if (record != null) break;
entityIDs.Add(currentEntityID);
//This call seems to cause the deadlock
currentEntity = await GetSystemEntityAsync(currentEntityID);
if (currentEntity != null && currentEntity.BackUpID.HasValue)
{
currentEntityID = (int) currentEntity.UseBackupID;
}
}
}
if (record != null)
{
records.Add(name, record);
}
}
return records;
}
public async Task<SystemEntity> GetSystemEntityAsync(int systemEntityID)
{
SystemEntity systemEntity = await DataLayer.GetSystemEntity(
scc => scc.SystemEntityID == systemEntityID);
return systemEntity;
}
Data Layer:
public async Task<SystemEntity> GetSystemEntity(Expression<Func<SystemEntity, bool>> whereExpression)
{
using (EntityContext dbContext = createDbInstance())
{
//This is the last line that the debugger in VS 2013 brings me to. Stepping into this returns to whatever called the API method, waiting endlessly.
return await
dbContext.SystemEntity.Include(sc => sc.OtherEntity).Where(whereExpression).FirstOrDefaultAsync();
}
}
To recap: I call GetSystemEntityAsync three times. The first two times, it completes successfully. The third time, it hangs. If I comment out the first two calls so they don't run at all, the third one still hangs. If I remove the await and use just a normal FirstOrDefault in the return statement of the data layer method, then everything completes just fine.
Note: I have to keep the GetSystemEntityAsync method asynchronous. I cannot alter it to be synchronous.
What are the possible sources of the deadlock I'm encountering? I'm out of ideas on how to solve it.
Which one of these async calls is not like the other?
This one, I suspect:
string text = BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp).Result.FirstOrDefault().Value;
Try changing it to this:
string text = (await BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp)).FirstOrDefault().Value;
The possible source of the deadlock is described by Stephen Cleary in his "Don't Block on Async Code" blog post.

Error while adding a row and then updating a row using EF

Currently I am attempting to add a new row to a database table through AJAX which is working fine. But then I try to update a different table and I get an error. Here is my code and the error I am encountering.
Error
The object cannot be attached because it is already in the object context. An object can only be reattached when it is in an unchanged state.
Line 41: _db.ChampionCounters.Attach(champion);
Code
[HttpPost]
public ActionResult VoteYes(int id)
{
string results;
if (Request.IsAuthenticated)
{
var checkFirst =
from c in _db.UserCounterLinks
where c.counterId == id && c.userName == User.Identity.Name
select c;
if (checkFirst.Any())
{
results = "You have already voted on this counter.";
return Json(results);
}
var userVoteLink = new UserCounterLink { counterId = id, userName = User.Identity.Name, userAgree = true };
_db.UserCounterLinks.AddObject(userVoteLink);
var champion = _db.ChampionCounters.SingleOrDefault(c => c.id == id);
if (champion != null)
{
champion.positiveVotes++;
_db.ChampionCounters.Attach(champion);
}
_db.SaveChanges();
results = "Voted";
} else
{
results = "You must be logged in to vote.";
}
return Json(results);
}
Summary
The code above is from the controller that handles the Ajax post. Like I said the userVoteLink table creates a record just fine. But when I try to update the other table ChampionCounters the error is thrown.
Thanks in advance!
You don't need to attach the instance because the context is already tracking that instance. Just remove the _db.ChampionCounters.Attach(champion); line.

Categories