Comparing Two Collections data with each other - c#

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()))

Related

Removing Rows in Entity Framework

What I am trying to create is when a user select an item, that item will disappear from the list of items. Some items can be submitted once and once it is submitted, the user not be able to submit the same item again. Submitted items will be logged to the database.
The issue I am having is figuring out what is wrong with my logic here as it is breaking and what can I do to improve this?
using (var db = new myDatabase())
{
var itemLists = db.GetAllItem().ToList();
var userSubmittedItems = db.GetAllUserItem("LoginID").ToList();
if (userSubmittedItems.Count > 0)
{
foreach (var submittedItems in userSubmittedItems)
{
foreach (var item in itemLists)
{
int itemID = item.ItemID;
int userItemID = userSubmittedItems.UserItemID;
if (itemID == userItemID && item.OneTime == true)
{
itemLists.Remove(item);
}
}
}
}
you're only removing the items in your collection itemLists, you are not performing anything in the database it self... for that you should, and imagining that your Entity for the Items is called ItemEntity do this:
using (var db = new myDatabase())
{
var itemLists = db.GetAllItem().ToList();
var userSubmittedItems = db.GetAllUserItem("LoginID").ToList();
if (userSubmittedItems.Count > 0)
{
foreach (var submittedItems in userSubmittedItems)
{
foreach (var item in itemLists)
{
int itemID = item.ItemID;
int userItemID = userSubmittedItems.UserItemID;
if (itemID == userItemID && item.OneTime == true)
{
itemLists.Remove(item);
db.ItemEntity.Remove(item); // mark for delete
}
}
}
db.SaveChanges(); // all marked items, if any, will now
// be committed in a db call
}
more on removing records with EF: Delete a single record from Entity Framework?

How I can realize parallel search in ObservableCollection?

I have an ObservableCollection, where Item has 2 properties(for example: Name and Id) and collection contains of 12k elements. So, i have a textbox, i want to search elements, which names contains my textbox value and add these elems in new collection.
in real-proj:
Silverlight, TreeView(its ItemSource is my collection) which dynamically changing. And TreeView changing in UI.
My problem is just in slowly rendering results of search. I thing if it'll be parallel - it saves me.
for example, some code im using:
private ObservableCollection<ICDDocumentItemViewModel> LinearSearch(string searchText)
{
var filteredCollection = new ObservableCollection<ICDDocumentItemViewModel>();
if (searchText.Length > 3)
{
foreach (var itemViewModel in _linearCollection)
{
if (!itemViewModel.Model.Name.ToLower().Contains(searchText.ToLower())) continue;
if (itemViewModel.Children.Count != 0)
{
itemViewModel.IsExpanded = true;
}
filteredCollection.Add(itemViewModel);
}
}
if(searchText.Length <= 3)
{
return new ObservableCollection<ICDDocumentItemViewModel>(ICDItemsViewModelsMain);
}
return filteredCollection;
}
there is no need to have parallel processing in place normally, this code should help you here.
private ObservableCollection<ICDDocumentItemViewModel> GetFiltered(string filter)
{
ObservableCollection<ICDDocumentItemViewModel> filteredCollection;
if (filter.Length > 3)
{
filteredCollection = new ObservableCollection<ICDDocumentItemViewModel>(_linearCollection.Where(x => x.Name.ToLower().Contains(filter)));
filteredCollection.ToList().ForEach(DetectChildren);
}
else
{
filteredCollection = new ObservableCollection<ICDDocumentItemViewModel>();
}
return filteredCollection;
}
private void DetectChildren(ICDDocumentItemViewModel item)
{
item.IsExpanded = item.Children.Any();
}

LinQ query, only one record submitted/inserted

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();
}
}

save children along with parent linq to sql

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);

Refresh UltraGrid's GroupBy Sort on child bands when ListChanged?

I am using Infragistics 2009 vol 1.
My UltraGrid is bound to a BindingList of business objects "A" having themself a BindingList property of business objects "B". It results in having two bands: one named "BindingList`1", the other one "ListOfB" thanks to the currency manager.
I would like to refresh the GroupBy sort of the grid whenever a change is performed on the child band through the child business object and INotifyPropertyChange.
If I group by a property in the child band which is a boolean (let's say "Active") and I subscribe to the event ListChanged on the bindinglist datasource with this event handler:
void Grid_ListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.ItemChanged)
{
string columnKey = e.PropertyDescriptor.Name;
if (e.PropertyDescriptor.PropertyType.Name == "BindingList`1")
{
ultraGrid.DisplayLayout.Bands[columnKey].SortedColumns.RefreshSort(true);
}
else
{
UltraGridBand band = ultraGrid.DisplayLayout.Bands[0];
UltraGridColumn gc = band.Columns[columnKey];
if (gc.IsGroupByColumn || gc.SortIndicator != SortIndicator.None)
{
band.SortedColumns.RefreshSort(true);
}
ColumnFilter cf = band.ColumnFilters[columnKey];
if (cf.FilterConditions.Count > 0)
{
ultraGrid.DisplayLayout.RefreshFilters();
}
}
}
}
the band.SortedColumns.RefreshSort(true) is called but It gives unpredictable results in the groupby area when the property Active is changed in the child band:
if one object out of three actives becomes inactive it goes from:
Active : True (3 items)
To:
Active : False (3 items)
Instead of (which is the case when I drag the column back and forth to the group by area)
Active : False (1 item)
Active : True (2 items)
Am I doing something wrong?
Is there a way to restore the expanded state of the rows when performing a RefreshSort(true); ?
Sounds like a bug to me - you should file one with Infragistics.
As to a workaround - this is not a nice solution and I haven't tested it but you could always try saving the sort-by (group) columns to a temp store, RefreshSort() on the band, then re-apply the sort-by (gorup) columns, and sort again?
ie. Remove group-by, then re-apply.
Nasty, but it might get you out of a bind.
Well, this is how I manage to solve the problem
var ultraGridBand = this.ExperimentGrid.DisplayLayout.Bands[0];
int nbGroup = ultraGridBand.Columns.All.Count(obj => ((UltraGridColumn) obj).IsGroupByColumn);
//if (ultraGridBand.Columns.All.Any(obj => ((UltraGridColumn)obj).SortIndicator != SortIndicator.None)))
if (nbGroup == 0)//no grouping
ultraGridBand.SortedColumns.RefreshSort(true);
else if (nbGroup > 0)
{
var expandedRows = new List<ExpandedRow>();
var rowLevel1 = this.ExperimentGrid.DisplayLayout.Rows;
ExtractExpandedRows(expandedRows, rowLevel1);
ultraGridBand.SortedColumns.RefreshSort(true);
SetExpandedRows(expandedRows, rowLevel1);
}
private static void SetExpandedRows(IEnumerable<ExpandedRow> expandedRows, RowsCollection rowLevel)
{
foreach (object obj in rowLevel.All)
{
var row = obj as UltraGridGroupByRow;
if (row != null)
{
var expandedRow = expandedRows.FirstOrDefault(x => x.Value == row.ValueAsDisplayText);
if (expandedRow != null)
{
row.Expanded = expandedRow.IsExpanded;
SetExpandedRows(expandedRow.SubRows, row.Rows);
}
}
}
}
private static void ExtractExpandedRows(ICollection<ExpandedRow> expandedRows, RowsCollection rowLevel)
{
foreach (object obj in rowLevel.All)
{
var row = obj as UltraGridGroupByRow;
if(row != null)
{
var expandedRow = new ExpandedRow() { Value = row.ValueAsDisplayText, IsExpanded = row.Expanded };
expandedRows.Add(expandedRow);
ExtractExpandedRows(expandedRow.SubRows, row.Rows);
}
}
}
And this is the object that contains the information
class ExpandedRow
{
public string Value { get; set; }
public bool IsExpanded { get; set; }
private readonly List<ExpandedRow> _subRows = new List<ExpandedRow>();
public List<ExpandedRow> SubRows { get { return _subRows; } }
}

Categories