I have two tables Rule and RuleCondition (one -> many).
people can add conditions at any time.
Suppose initially he adds two conditions.
He can comeback and add another condition also can update the conditions that are already added.
I am able to save the updated conditions, but not able to insert the extra condition he added.
Below is my code, and it is failing at
rule.RuleConditions.Add(oRuleCon); -- Entity set was modified during enumaration
If I use the approach
oAngieCtxt.RuleConditions.InsertOnSubmit(oRuleCon);
it is not at all inserting the data.
can somebody advise how to handle?
public ActionResult saveMetricRule(Rule rule)
{
bool IsNew = rule.RuleId == 0;
using (NewAngieDataContext oAngieCtxt = new NewAngieDataContext(new CSConfigurationMgr().GetConnectionString(ConnectionStringKey.Angie)))
{
if (IsNew)
oAngieCtxt.Rules.InsertOnSubmit(rule);
else
{
RuleCondition oRuleCon = null;
foreach (RuleCondition childItem in rule.RuleConditions)
{
if (childItem.RuleConditionId == 0)
{
oRuleCon = new RuleCondition();
oRuleCon.Points = childItem.Points;
oRuleCon.ConditionValue = childItem.ConditionValue;
oRuleCon.ToOperatorId = childItem.ToOperatorId;
oRuleCon.Sort = childItem.Sort;
rule.RuleConditions.Add(oRuleCon);
// oAngieCtxt.RuleConditions.InsertOnSubmit(oRuleCon);
}
else
{
oRuleCon =
oAngieCtxt.RuleConditions
.Where(CON => CON.RuleConditionId == childItem.RuleConditionId)
.FirstOrDefault();
oRuleCon.Points = childItem.Points;
oRuleCon.ConditionValue = childItem.ConditionValue;
oRuleCon.ToOperatorId = childItem.ToOperatorId;
oRuleCon.Sort = childItem.Sort;
}
}
oAngieCtxt.Rules.Attach(rule);
oAngieCtxt.Refresh(RefreshMode.KeepCurrentValues, rule);
}
oAngieCtxt.SubmitChanges();
}
return this.Json(new
{
msg = "Successful save.",
ruleId = rule.RuleId
});
}
You can't add an item to a list that you're enumerating over. Since you're looping over the rule.RuleConditions, you can't add to it inside the foreach loop. Instead, you can add to a temporary list and then add all items from that list to the rule.RuleConditions after the foreach.
var newRuleConditions = new List<RuleCondition>();
foreach (RuleCondition childItem in rule.RuleConditions)
{
if (childItem.RuleConditionId == 0)
{
oRuleCon = new RuleCondition();
oRuleCon.Points = childItem.Points;
oRuleCon.ConditionValue = childItem.ConditionValue;
oRuleCon.ToOperatorId = childItem.ToOperatorId;
oRuleCon.Sort = childItem.Sort;
//add to temporary list
newRuleConditions.Add(oRuleCon);
oAngieCtxt.RuleConditions.InsertOnSubmit(oRuleCon);
}
else
{
...
}
}
//add all new rule conditions
rule.RuleConditions.AddRange(newRuleConditions);
Related
I have two observable collections. 1. TruckItems 2. TruckItemsComparison. Both are exactly the same.
I load data into the first TruckItems collection from EF6, then 10 seconds later I load data into the second collection TruckItemsComparison. Now the new data that was added in my 2nd collection might have been updated lately from another source and I need to only add the latest data that does not yet exist in my first collection.
I want to check if ANY of the id's from my 2nd collection does not match any of the id's in my first collection and then only add the items that does not match.
CODE:
Here is where I load my data:
private async void LoadTrucks()
{
using (TruckServiceClient service = new TruckServiceClient())
{
var items = await service.GetTrucksAsync();
if (TruckItems.Count == 0)
{
foreach (var item in items)
{
TruckItems.Add(new TruckItems
{
TruckId = item.TruckId,
TruckQuoteId = item.QuoteId,
TruckPhaseId = item.CurrentPhaseId,
TruckChassisManufacturer = item.ChassisManufacturer,
TruckChassisModel = item.ChassisModel,
TruckStatus = item.Status,
TruckJobNumber = item.JobNumbers,
TruckAddedBy = item.AddedBy,
TruckClientName = item.ClientName,
TruckClientSurname = item.ClientSurname,
TruckClientDetail = item.ClientDetail,
TruckCurrentPhase = item.CurrentPhase
});
}
}
foreach (var item in items)
{
TruckItemsComparison.Add(new TruckItems
{
TruckId = item.TruckId,
TruckQuoteId = item.QuoteId,
TruckPhaseId = item.CurrentPhaseId,
TruckChassisManufacturer = item.ChassisManufacturer,
TruckChassisModel = item.ChassisModel,
TruckStatus = item.Status,
TruckJobNumber = item.JobNumbers,
TruckAddedBy = item.AddedBy,
TruckClientName = item.ClientName,
TruckClientSurname = item.ClientSurname,
TruckClientDetail = item.ClientDetail,
TruckCurrentPhase = item.CurrentPhase
});
}
}
}
And here is where I want to compare my two collections:
public void UpdateTrucks()
{
LoadTrucks();
if (TruckItems.Count != 0)
{
var truckItemsId = TruckItems.Where(x => x.TruckId != 0).First().TruckId;
foreach (var item in TruckItemsComparison.Where(x => x.TruckId != truckItemsId))
{
TruckItems.Add(item);
}
}
}
My problem is that it adds the data from both the two collections together, regardless if the id's correspond or not. Clearly my logic here does not work, so can anyone please show me a way of how I can compare the data and only insert id's that do not yet exist in my TruckItems collection. Thanks and please let me know if you need any more information.
You can enumerate through each of the items in your TruckItemsComparison by using Except:
public void UpdateTrucks()
{
LoadTrucks();
if (TruckItems.Count != 0)
{
foreach (var item in TruckItemsComparison.Except(TruckItems))
{
TruckItems.Add(item);
}
}
}
If all you want to do is compare the Ids of your TruckItems then you can implement your own IEqualityComparer:
internal class TruckItemsComparer : IEqualityComparer<TruckItems>
{
#region IEqualityComparer Members
public bool Equals(TruckItems x, TruckItems y)
{
return (((x == null) && (y == null)) ||
((x != null) && (y != null) && x.TruckId == y.TruckId));
}
public int GetHashCode(TruckItems obj)
{
return obj. TruckId.GetHashCode();
}
#endregion
}
And then use like so:
foreach (var item in TruckItemsComparison.Except(TruckItems, new TruckItemsComparer()))
I am trying to stop my custom OnSaving event after it has been applied to the first item in the save chain.
but so far I have not been able to, and I end up with a stackoverflow exception.
Is there a simple way of doing this ?
Best regards,
Robin
private void AddOrRemoveRedirectingItemIdFromSavingItemIdList(Item savingItem, SitecoreEventArgs sitecoreEventArgs)
{
ItemLink[] referers = Globals.LinkDatabase.GetReferrers(savingItem);
var guidList = new List<ID>();
foreach (ItemLink link in referers)
{
// checking the database name of the linked Item
if (!link.SourceDatabaseName.Equals(Context.ContentDatabase.Name, StringComparison.CurrentCultureIgnoreCase))
{
continue;
}
Item item = Context.ContentDatabase.Items[link.SourceItemID, savingItem.Language];
// adding the Item to an array if the Item is not null
if (item == null || item.Fields["301Redirect"] == null || item.Fields["301RedirectedTo"] == null)
{
continue;
}
// Update the saving item ids
CheckboxField redirectField = item.Fields["301Redirect"];
if (redirectField.Checked)
{
guidList.Add(item.ID);
}
}
if (guidList.Any())
{
this.SaveIDsToEditingItem(savingItem, guidList, false);
}
}
private void SaveIDsToEditingItem(Item editingItem, IEnumerable<ID> guidList, bool forceModified)
{
Field redirectedToFromItemId = editingItem.Fields["301RedirectedToFromItemId"];
using (new EditContext(editingItem))
{
// Saving the redirected items ids
string redirectedToFromItemIdOld = redirectedToFromItemId.Value;
string redirectedToFromItemIdNew = string.Join("\n", guidList.Select(guid => guid.ToString()));
// if the values are not changed
if (redirectedToFromItemIdNew.Equals(redirectedToFromItemIdOld))
{
return;
}
redirectedToFromItemId.Value = redirectedToFromItemIdNew;
if (forceModified)
{
editingItem.RuntimeSettings.ForceModified = true;
}
}
}
}
You can do this 2 ways. The better way would be to remove the using (new EditingContext(editingItem) section from the SaveIDsToEditingItem. In the OnItemSaving event, any changes made to the savingItem would be kept.
Alternatively, if you need to use the editing context for some reason you need to use an EventDisabler in your SaveIDsToEditingItem method:
private void SaveIDsToEditingItem(Item editingItem, IEnumerable<ID> guidList, bool forceModified)
{
Field redirectedToFromItemId = editingItem.Fields["301RedirectedToFromItemId"];
using (new EventDisabler())
{
using (new EditContext(editingItem))
{
// Saving the redirected items ids
string redirectedToFromItemIdOld = redirectedToFromItemId.Value;
string redirectedToFromItemIdNew = string.Join("\n", guidList.Select(guid => guid.ToString()));
// if the values are not changed
if (redirectedToFromItemIdNew.Equals(redirectedToFromItemIdOld))
{
return;
}
redirectedToFromItemId.Value = redirectedToFromItemIdNew;
if (forceModified)
{
editingItem.RuntimeSettings.ForceModified = true;
}
}
}
}
This will prevent the OnSaving event from being fired again.
I have this C# and linq to database to get all rows of data from database
var getOldAttachment = _context.ca_Attachments.Where(x => x.CaseId == getCase[0].Id && x.isDeleted == false).ToList();
Than I want to use a foreach to re-insert the exact row of data into database with updates of new datacolumn, in simple words is just to duplicate the same data row but with different values. the data row contains Id, creator, attachmentid, lastupdateon. with values of : 1, tester, 12345,2015-11-16 11:49:50.810 respectively i just want to change the value of editor to current use which call editor. What am i suppose to put in the ???? portion?
if (getOldAttachment != null && getOldAttachment.Count > 0)
{
//foreach (??????)
//{
// data.ca_Attachments.Add(new ca_Attachment
// {
// AttachmentId = getOldAttachment.attachmentId,
// creator = editor,
// LastUpdatedOn = _startTime,
// });
//}
}
A note: You don't need to check for null after ToList(). It will never be null. You also don't need to check for Count > 0, since we're going to iterate it (and it will not execute if there are no items anyway).
You can simply write:
var oldAttachments = _context.ca_Attachments
.Where(x => x.CaseId == getCase[0].Id && !x.isDeleted)
.ToList();
foreach (var oldAttachment in oldAttachments)
{
data.ca_Attachments.Add(new ca_Attachment
{
AttachmentId = oldAttachment.attachmentId,
creator = editor,
LastUpdatedOn = _startTime,
});
}
Here's one option using ForEach:
getOldAttachment.ForEach(att => {
_context.ca_Attachments.Add(new ca_Attachment
{
AttachmentId = att.attachmentId,
creator = editor,
LastUpdatedOn = _startTime,
});
});
This uses _context to add a new attachment instead of data -- not sure what data is...
if (getOldAttachment != null && getOldAttachment.Count > 0)
{
for(var i = 0; i < getOldAttachment.Count; i++)
{
//this is how to populate the data from list
//sample only
ca_Attachment.AttachmentId = getOldAttachment[i].AttachmentId;
//do the insert code
}
}
I just wanna ask if there is someone here that have already made a breadcrumbs in Sitecore. I'm currently doing a Sitecore 8 MVC project that needs to have a breadcrumbs.
Currently I saw this website http://blog.ryanbailey.co.nz/2015/05/breadcrumbs-for-pages-in-sitecore.html. But It doesn't work for me yet because I don't know what to reference.
I just need to know how to get every item in the path of my current page I can handle it already.
Thanks
Something like this should do it:
public ICollection<Item> GetBreadcrumbs(Item current, SiteContext site)
{
Item homeItem = site.StartItem;
List<Item> breadcrumbs = new List<Item>();
while (current != null)
{
// You may want to add additional logic to opt in/out of
// the breadcrumb based on a template/field
breadcrumbs.Add(current);
if (current == homeItem)
break;
current = current.Parent;
}
breadcrumbs.Reverse();
return breadcrumbs;
}
And then:
var breadcrumbs = GetBreadcrumbs(Context.Item, Context.Site);
You can take the current item and then take all the ancestors of it.
var ancestors = currentItem.Axes.GetAncestors().ToList();
Then you can get home item and filter the ancestors to remove sitecore and content nodes.
ancestors = ancestors.SkipWhile(i => i.ID != home.Id.ToID()).ToList();
public void GetBreadcrumbs(Item ParentItem)
{
List<BredCrumbDetails> lstBreadCrumbs = new List<BredCrumbDetails>();
string strcurrenttitle = ParentItem.Name;
Item currentitem = ParentItem;
int i = 0;
while (currentitem != null)
{
var ItemTemplateid = currentitem.TemplateID.ToString();
var FolderTemplateId = "{}";
if (ItemTemplateid != FolderTemplateId) //here we are removing folders
{
BredCrumbDetails bcDetails = new BredCrumbDetails();
if (i == 0)
{
bcDetails.BCPageLink = null;
bcDetails.Title = currentitem.Name;
bcDetails.IsVisible = true;
lstBreadCrumbs.Add(bcDetails);
}
else
{
bcDetails.BCPageLink = currentitem.Paths.FullPath;
bcDetails.Title = currentitem.Name;
bcDetails.IsVisible = true;
lstBreadCrumbs.Add(bcDetails);
}
i++;
if (currentitem.Name == ("Home"))
{
break;
}
currentitem = currentitem.Parent;
}
else
{
i++;
currentitem = currentitem.Parent;
}
}
lstBreadCrumbs.Reverse();
rptCrumbs.DataSource = lstBreadCrumbs;
rptCrumbs.DataBind();
}
I'm trying to insert only males teachers into the "MaleTeachers" table, but after program is executed I see only one teacher in that table. In addition, I have more then one teacher in the "Stuffs" table, but inserted one is the last that matches "if" criteria. Could you correct this code please. Service implementation:
public void AddTeachers()
{
DataClasses1DataContext data = new DataClasses1DataContext();
DataClasses2DataContext data2 = new DataClasses2DataContext();
MaleTeacher tchr = new MaleTeacher();
foreach (var d in data.Stuffs)
{
if (d.stuffSex == true && d.stuffJob == "Teacher")
{
tchr.teacherName = d.stuffName;
tchr.teacherAge = d.stuffAge;
tchr.teacherJob = d.stuffJob;
tchr.teacherDepartm = "geology";
data2.MaleTeachers.InsertOnSubmit(tchr);
}
}
data2.SubmitChanges();
}
you foreach loop should be.
foreach (var d in data.Stuffs)
{
if (d.stuffSex == true && d.stuffJob == "Teacher")
{
MaleTeacher tchr = new MaleTeacher();
tchr.teacherName = d.stuffName;
tchr.teacherAge = d.stuffAge;
tchr.teacherJob = d.stuffJob;
tchr.teacherDepartm = "geology";
data2.MaleTeachers.InsertOnSubmit(tchr);
}
}
You are creating only one intance and then modifying it again and again... instead you should create a different MaleTeacher instance on every time.
MaleTeacher tchr = new MaleTeacher();
foreach (var d in data.Stuffs)
{
if (d.stuffSex == true && d.stuffJob == "Teacher")
{
tchr.teacherName = d.stuffName;
tchr.teacherAge = d.stuffAge;
tchr.teacherJob = d.stuffJob;
tchr.teacherDepartm = "geology";
data2.MaleTeachers.InsertOnSubmit(tchr);
tchr = new MaleTeacher();
}
}