Update variable in foreach - c#

I have an issue related to updating an object by reference and not sure exactly what is going on.
I need to delete a list of rules and for logging I need to load another field
ruleItem.ReferencedItemValue = eventEntity.Title;
When
builder.LogDelete(showRule, showRuleResource.ToAuditLog(), "Logic Rule");
is called the ReferencedItemValue is not populated.
Any ideas, suggestions, alternatives?
Thanks
CODE:
public void DeleteCustomLogicRule(int[] ruleIds){
var rules = uow.Context.ShowRules.Where(sr => ruleIds.Contains(sr.Id)).ToList();
if (rules.Any())
{
var showId = rules.FirstOrDefault().ShowId;
var builder = AuditBuilder.FromShowId(showId);
rules.ForEach(showRule =>
{
var showRuleResource = ToShowRuleResource(showRule);
FillReferenceValue(showRuleResource);
builder.LogDelete(showRule, showRuleResource.ToAuditLog(), "Logic Rule");
});
uow.Context.SaveChanges();
builder.ToDatabase();
}
}
private void FillReferenceValue(ShowRuleResource showRuleResource)
{
foreach (var ruleItem in showRuleResource.ItemsPredicateAppliesTo.ToList())
{
FillRuleItem(ruleItem);
}
}
private void FillRuleItem(RuleItemResource ruleItem)
{
var eventEntity = uow.Context.Events.FirstOrDefault(e => e.Id == ruleItem.ReferencedItemId.Value);
if (eventEntity != null)
ruleItem.ReferencedItemValue = eventEntity.Title;
}

try this one:
rules.ForEach(showRule =>
{
var item = showRule;
var showRuleResource = ToShowRuleResource(item);
FillReferenceValue(showRuleResource);
builder.LogDelete(item, showRuleResource.ToAuditLog(), "Logic Rule");
});

Start to dig from this function
private void FillRuleItem(RuleItemResource ruleItem)
It seems like this exspressiion
var eventEntity = uow.Context.Events.FirstOrDefault(e => e.Id == ruleItem.ReferencedItemId.Value);
is null.

Related

Performance issue when performing operations on entity objects

Im facing performance issue in below code in multiple foreach loops. First im getting a list of ReturnDetails and then based on detail id get the HandlingInfo object. Then based on value of action, update the ReturnsDetail Object again.
It take more than a minute for loading 3000 records of ReturnsDetail. While debugging locally, it runs for infinite amount of time.
Please let me know in anyway i can refactor this code .
Thanks for your help.
lstReturnsDetail = dcReturnsService.GetReturnDetailsInfo(header_id);
List<HandlingInfo> lstHandlingInfo = null;
foreach (ReturnsDetail oReturnsDetail in lstReturnsDetail)
{
using (DCReturns_Entities entities = new DCReturns_Entities())
{
lstHandlingInfo = entities.HandlingInfoes.Where(f => f.detail_id == oReturnsDetail.id).ToList();
if(lstHandlingInfo != null)
{
foreach (HandlingInfo oHandlingInfo in lstHandlingInfo)
{
if (oHandlingInfo.action == "DST")
{
oReturnsDetail.destroy += Convert.ToInt32(oHandlingInfo.qty);
}
else if (oHandlingInfo.action == "SHP")
{
oReturnsDetail.to_shop += Convert.ToInt32(oHandlingInfo.qty);
}
else if (oHandlingInfo.action == "RBX")
{
oReturnsDetail.in_stock += Convert.ToInt32(oHandlingInfo.qty);
}
}
}
}
oReturnsDetail.received_qty = oReturnsDetail.destroy + oReturnsDetail.to_shop + oReturnsDetail.in_stock;
}
dgReturnsDetail.DataSource = lstReturnsDetail.OrderByDescending(g => g.id).ToList();
Session[DCReturnsConstants.Returns_Detail_Entity] = lstReturnsDetail;
dgReturnsDetail.DataBind();
this is su-do code! but you should get the jist.
//modify this to return all of them into mem, and then filter on this...
//if it can not be done here then do below..
var lstReturnsDetail = dcReturnsService.GetReturnDetailsInfo(header_id);
//then create a list here which fetches all,
List<[type]> somelist
List<int> listId = lstReturnsDetail.select(x=>x.id).tolist();
using (var db = new DCReturns_Entities())
{
somelist = db.HandlingInfoes.Where(f => listId.Contains( f.detail_id)).ToList();
}
foreach (ReturnsDetail oReturnsDetail in lstReturnsDetail)
{
//performance issue is here
//using (DCReturns_Entities entities = new DCReturns_Entities())
//{
// lstHandlingInfo = entities.HandlingInfoes.Where(f => f.detail_id == oReturnsDetail.id).ToList();
//}
//insead fetach all before, into mem and filter from that list.
var lstHandlingInfo = somelist.Where(f => f.detail_id == oReturnsDetail.id).ToList();
//code ommited for reaablity
}
//code ommited for reaablity

how to change change ui with async in xamarin forms

I try to develop a mobile app in xamarin forms.
I have news list and i am using SQLite for store that.
When my main page open, before i get the news from SQLite and then i try to get new news from web API. I can save the new news in SQLite but my UI hasn't changed. How can i fix that?
public MainPage()
{
InitializeComponent();
database = new Helper.xxxDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "xxx.db3"));
SetLocalDBMainNews();
Task.Run(async () => { await GetNewsAsync(); });
}
void SetLocalDBMainNews()
{
if(database.TableExists("News"))
{
List<News> newsList = database.GetNewsData();
if (newsList.Count > 0)
{
MaiNewsList.ItemsSource = newsList.Where(x => x.Type.Equals((int)NewsType.MainNews)).OrderBy(x => x.Sort).ToList();
}
}
else
database.CreateNewsTable();
}
private async Task GetNewsAsync()
{
try
{
var register = database.GetRegisterData();
string url = "http://xxx.azurewebsites.net/api/News/GetPublishedNews";
var response = Tools.Send(url, "GET", register.Token);
var result = JsonConvert.DeserializeObject<ApiResponse<List<News>>>(response);
if (result.HasError == false)
{
var newsList = result.Value;
database.DeleteAllNews();
foreach(var n in newsList)
{
database.Insert(n);
}
MaiNewsList.ItemsSource = newsList.Where(x => x.Type.Equals((int)NewsType.MainNews)).OrderBy(x => x.Sort).ToList();
}
}
catch{}
}
The code works for saving new news to SQLite but i couldn't bind the news to UI in async.
Edit :
After jason's answer, here is the my code latest version
Device.BeginInvokeOnMainThread solve the my problem.
private async Task GetNewsAsync()
{
try
{
var register = database.GetRegisterData();
string url = "http://xxx.azurewebsites.net/api/News/GetPublishedNews";
var response = Tools.Send(url, "GET", register.Token);
var result = JsonConvert.DeserializeObject<ApiResponse<List<News>>>(response);
if (result.HasError == false)
{
var newsList = result.Value;
database.DeleteAllNews();
foreach(var n in newsList)
{
database.Insert(n);
}
Device.BeginInvokeOnMainThread(() =>
{
MaiNewsList.ItemsSource = newsList.Where(x => x.Type.Equals((int)NewsType.MainNews)).OrderBy(x => x.Sort).ToList();
});
}
}
catch
{
}
}
UI changes need to happen on the UI thread using BeginInvokeOnMainThread
Device.BeginInvokeOnMainThread( () =>
{
MaiNewsList.ItemsSource = newsList.Where(x => x.Type.Equals((int)NewsType.MainNews)).OrderBy(x => x.Sort).ToList();
});

UWP Event on content changed

I want to observe on a folder. Like i want a Event When the content is changed.
I found this
var options = new Windows.Storage.Search.QueryOptions
{
FolderDepth = Windows.Storage.Search.FolderDepth.Deep
};
var query = Folder.CreateFileQueryWithOptions(options);
query.ContentsChanged += QueryContentsChanged;
var files = await query.GetFilesAsync();
private void QueryContentsChanged(IStorageQueryResultBase sender, object args)
{
//Code here
}
But the problem with this is I can't find which file caused the event and i even can't know what caused the Event (Like Modify , Create , Delete or Rename of file) How to get these details?
I used this code
public async void MonitorFolder()
{
var options = new Windows.Storage.Search.QueryOptions
{
FolderDepth = Windows.Storage.Search.FolderDepth.Deep
};
var query = Folder1.CreateFileQueryWithOptions(options);
query.ContentsChanged += QueryContentsChanged;
var files = await query.GetFilesAsync();
await addtoOld(Folder1, Old);
}
private async void addtoOld(StorageFolder folder1, List<FDate> old)
{
var files = await folder1.GetFilesAsync();
foreach (var file in files)
{
BasicProperties basicProperties = await file.GetBasicPropertiesAsync();
FDate f = new FDate
{
Path = file.Path,
Id = file.FolderRelativeId,
Modified = basicProperties.DateModified,
Change = ChangeType.NoChange,
FileType = Type.File
};
old.Add(f);
}
var folders = await folder1.GetFoldersAsync();
foreach (var folder in folders)
{
BasicProperties basicProperties = await folder.GetBasicPropertiesAsync();
FDate f = new FDate
{
Path = folder.Path,
Id = folder.FolderRelativeId,
Modified = basicProperties.DateModified,
Change = ChangeType.NoChange,
FileType = Type.Folder
};
old.Add(f);
addtoOld(folder, old);
}
return;
}
private async void QueryContentsChanged(IStorageQueryResultBase sender, object args)
{
New.Clear();
List<FDate> changed = new List<FDate>();
await addtoOld(Folder1, New);
foreach(var f in New)
{
var f1 = getFile(f);
if (f1 != null)
{
if (f1.Modified < f.Modified)
{
f1.Change = ChangeType.Modified;
changed.Add(f1);
}
Old.Remove(f1);
}
else
{
f.Change = ChangeType.Created;
changed.Add(f);
}
}
foreach (var f in Old)
{
f.Change = ChangeType.Deleted;
changed.Add(f);
}
Old = New;
foreach (var f in changed)
{
if(f.FileType== Type.File)
{
if (f.Change == ChangeType.Modified)
{
//code here
}
if(f.Change == ChangeType.Created)
{
//Created code here
}
if(f.Change == ChangeType.Deleted)
{
//Deleted code here
}
}
else
{
if (f.Change == ChangeType.Created)
{
//Created code here
}
if(f.Change == ChangeType.Deleted)
{
//Deleted code here
}
}
}
private FDate getFile(FDate f)
{
foreach(var fi in Old)
{
if (f.Name == fi.Name)
return fi;
}
return null;
}
This code is not working properly I looks like it is because the addtoOld is async The code can't be substituted because it is recursive. and the function can't be made sync it has many await how do i solve this?
Note:OLD and New are Lists ChangeType and Type are enums
According to the following blog post, there is unfortunately no way to identify the reason of the event and there is also no information about affected items.
File system change notifications in WinRT: http://lunarfrog.com/blog/filesystem-change-notifications
So I guess you will have to go through all files and check their Properties property to determine when each file was last modified, created etc.: https://learn.microsoft.com/en-us/uwp/api/windows.storage.storagefile

if record exists delete it?

I am using this code to create a record in the ClientAccountAccess table. However there should only ever be one record in this table at any time. so if this function is called I first want to check if a record exists, if it does delete it then add the new record.
private static void SetAccessCode(string guidCode)
{
using (EPOSEntities db = new EPOSEntities())
{
//so here would I say something like (see below)
ClientAccountAccess client = new ClientAccountAccess();
client.GUID = guidCode;
db.AddToClientAccountAccesses(client);
db.SaveChanges();
}
}
//
ClientAccountAccess clientAccessCodes = db.ClientAccountAccesses
.OrderByDescending(x => x.Id)
.Take(1)
.Single();
if clientAccessCodes.exists()
db.DeleteObject(clientAccessCodes);
db.SaveChanges();
Try something like this...
bool doesItExistAlready = (from caa in db.ClientAccountAccesses
where css.id == guidCode
select caa).Any();
if (doesItExistAlready)
{
// Delete old record
db.DeleteObject(PUTIDENTIFIERHERE);
}
// Add new record
ClientAccountAccess client = new ClientAccountAccess();
client.GUID = guidCode;
db.AddToClientAccountAccesses(client);
Do you really need to remove it? If you don't you can do this:
private static void SetAccessCode(string guidCode)
{
using (EPOSEntities db = new EPOSEntities())
{
var c= db.ClientAccountAccesses.FirstOrDefault(f=>f.GUID==guidCode);
if(c!=null)
return;
var client = new ClientAccountAccess(){GUID=guidCode};
db.AddToClientAccountAccesses(client);
db.SaveChanges();
}
}
Then you will only insert it if it do not already exists
If you need to remove it before creating the object. You can do this:
private static void SetAccessCode(string guidCode)
{
using (EPOSEntities db = new EPOSEntities())
{
var c= db.ClientAccountAccesses.FirstOrDefault(f=>f.GUID==guidCode);
if(c!=null)
{
db.ClientAccountAccesses.DeleteObject(c);
db.SaveChanges();
}
var client = new ClientAccountAccess(){GUID=guidCode};
db.AddToClientAccountAccesses(client);
db.SaveChanges();
}
}
If you can update the object you can do something like this:
private static void SetAccessCode(string guidCode)
{
using (EPOSEntities db = new EPOSEntities())
{
var c= db.ClientAccountAccesses.FirstOrDefault(f=>f.GUID==guidCode);
if(c==null)
{
c=new ClientAccountAccess();
db.AddToClientAccountAccesses(client);
}
c.GUID=guidCode;
db.SaveChanges();
}
}

Updating multiple records that share a many to many relationship fails

Details
I have 2 tables (Procedures, Surgeons) with a lookup table (ProcSurg) to create a many to many relationship.
scar_Requests scar_Procedures scar_ProcSurg scar_Surgeons
------------- --------------- ------------- -------------
RequestID <> ProcedureID <> ProcedureID(fk) <> SurgeonID
... RequestID SurgeonID(fk) ...
...
A single request can have multiple procedures and each procedure can have multiple surgeons.
Everything saves correctly until I have 2 procedures each that share the same Surgeon.
Error: InvalidOperationException was unhandled
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
I separated out the code for saving this part of the record to try to isolate my problem..
Addprocedures is a class that contains 1 Procedure and a list of Surgeons
class Procedure
{
public scar_Procedures Procedure { get; set; }
public List<scar_Surgeons> Surgeons { get; set; }
public void RemoveSurgeon(int SurgeonID)
{
Surgeons.Remove(Surgeons.Where(x => x.SurgeonID == SurgeonID).FirstOrDefault());
}
public Procedure()
{
Surgeons = new List<scar_Surgeons>();
}
}
Saving code: using DBContext
private void SaveProcSurg()
{
using (MCASURGContext db2 = new MCASURGContext())
{
foreach (Procedure p in AddProcedures)
{
if (p.Procedure.RequestID == 0)
{
p.Procedure.RequestID = ReqID;
}
p.Procedure.scar_Surgeons.Clear();
foreach (scar_Surgeons s in p.Surgeons)
{
if (db2.ChangeTracker.Entries<scar_Surgeons>().Where(x => x.Entity.SurgeonID == s.SurgeonID).FirstOrDefault() == null)
{
db2.scar_Surgeons.Attach(s);
}
p.Procedure.scar_Surgeons.Add(s);
}
if (p.Procedure.ProcedureID == 0)
{
db2.scar_Procedures.Add(p.Procedure);
db2.Entry(p.Procedure).State = System.Data.Entity.EntityState.Added;
}
else
{
db2.scar_Procedures.Attach(p.Procedure);
db2.Entry(p.Procedure).State = System.Data.Entity.EntityState.Modified;
}
}
db2.SaveChanges();
}
}
I've tried several different ways of saving the record and this is the closest I've come to doing it correctly.
I feel like it has something to do with the way I'm attaching the surgeons to the entity and then to the procedure. Any help, idea's or suggestions on where I can find an answer would be great!
I've been searching google endlessly for over a week and I've been trying to wrap my mind around what exactly Entity Framework is doing but I'm still pretty new to this.
Edited 9/24/2013
Sorry this is the complete code snippet from the comments section with the req variable included
//Internal variable
private scar_Requests req;
private List<Procedure> AddProcedures = new List<Procedure>();
//Gets a scar_Request from the DB
private void GetRequest()
{
using (MCASURGContext db = new MCASURGContext())
{
req = db.scar_Requests.Include("scar_Procedures.scar_Surgeons").Include("scar_Status").Include("scar_Users.scar_Service").Where(x => x.RequestID == ReqID).FirstOrDefault();
foreach (scar_Procedures p in req.scar_Procedures) { AddProcedures.Add(new Procedure() { Proc = p, Surgeons = p.scar_Surgeons.ToList() }); }
}
}
Keeping with good form I'll post my answer since I think I figured it out. Maybe it will help someone in the future.
I completely re-wrote the saving and cut out a lot of useless code that I was using before and less calls to the DB. There was other methods that I didn't post above that saved other parts of the record that I condensed into a single method.
Basically I get the record and its joined tables from the DB and iterate through all the fields/joined tables that need to be updated and save it back to the DB. (Seems super obvious now but I tried this way before and I must have had something wrong because it didn't work the first few times I tried it this way.)
I don't know if its 100% correct or written up to normal coding standards and I still have some final tweaking to do before its completely done.
private void SaveProcSurg()
{
using (MCASURGContext db2 = new MCASURGContext())
{
//Get Record from DB
scar_Requests sReq = db2.scar_Requests.Include("scar_Users").Include("scar_Status").Include("scar_Procedures.scar_Surgeons").Where(x => x.RequestID == ReqID).FirstOrDefault();
//Update Record fields
sReq.CreationDate = req.CreationDate == null ? DateTime.Now : req.CreationDate = req.CreationDate;
sReq.DateOfSurgery = dtpDateOfSurgery.Value;
sReq.IsDeleted = false;
sReq.IsScheduled = false;
sReq.LatexAllergy = cbLatexAllergy.Checked;
sReq.ModifiedDate = DateTime.Now;
sReq.MRN = txtMRN.Text;
sReq.PatientName = txtPatientName.Text;
foreach (RadioButton rb in gbPatientType.Controls) if (rb.Checked == true) sReq.PatientType = rb.Text;
sReq.PreOpDiagnosis = txtPreOpDiag.Text;
sReq.PrimarySurgeon = txtPrimarySurgeon.Text;
sReq.PrivateComment = txtPrivateComment.Text;
sReq.PublicComment = txtPublicComment.Text;
sReq.RequestID = ReqID;
sReq.StatusID = req.StatusID;
sReq.UserID = req.UserID;
//Update Users/Status
sReq.scar_Users = db2.scar_Users.Where(x => x.UserID == sReq.UserID).FirstOrDefault();
sReq.scar_Status = db2.scar_Status.Where(x => x.StatusID == req.StatusID).FirstOrDefault();
//Attach to DBContext
db2.scar_Requests.Attach(sReq);
//Update Procedures
foreach (Procedure p in AddProcedures)
{
scar_Procedures pro = sReq.scar_Procedures.Where(x => x.ProcedureID == p.Proc.ProcedureID && p.Proc.ProcedureID != 0).FirstOrDefault();
if (pro != null)
{
pro.EnRecovery = p.Proc.EnRecovery;
pro.IsPrimary = p.Proc.IsPrimary;
pro.Laterality = p.Proc.Laterality;
pro.OrthoFastTrack = p.Proc.OrthoFastTrack;
pro.ProcedureID = p.Proc.ProcedureID;
pro.ProcedureText = p.Proc.ProcedureText;
pro.RequestID = ReqID;
pro.Site = p.Proc.Site;
}
else
{
pro = new scar_Procedures();
pro.EnRecovery = p.Proc.EnRecovery;
pro.IsPrimary = p.Proc.IsPrimary;
pro.Laterality = p.Proc.Laterality;
pro.OrthoFastTrack = p.Proc.OrthoFastTrack;
pro.ProcedureID = p.Proc.ProcedureID;
pro.ProcedureText = p.Proc.ProcedureText;
pro.RequestID = ReqID;
pro.Site = p.Proc.Site; ;
pro.scar_Requests = sReq;
}
//Update Surgeons
pro.scar_Surgeons.Clear();
foreach (scar_Surgeons s in p.Surgeons)
{
pro.scar_Surgeons.Add(db2.scar_Surgeons.Where(x=> x.SurgeonID == s.SurgeonID).FirstOrDefault());
}
}
//Set State and Save
db2.Entry(sReq).State = System.Data.Entity.EntityState.Modified;
db2.SaveChanges();
}
}

Categories

Resources