I am trying to filter the ICollection but the filter is not getting applied and instead it gives me all records. is there any issue in the predicate ? so there are two methods where the filter is applied on collection. First it filters records for SW_Version and then in the second filter it filters for matching id. basically i am implementing search functionality.
public void Updateswlist()
{
CRmappings2 = new ObservableCollection<SPFetchCREntity>(crentities.ToList());
AllCRSP = CollectionViewSource.GetDefaultView(CRmappings2);
SearchMU = SelectedSW.SW_Version;
AllCRSP.Filter = obj =>
{
SPFetchCREntity entity = obj as SPFetchCREntity;
return obj != null && entity.SW_Version == SearchMU.ToString();
};
AllCRSP.Refresh();
2nd Filter
public void searchMUID()
{
AllCRSP.Filter = obj =>
{
SPFetchCREntity entity = obj as SPFetchCREntity;
return obj != null && entity.MU_Identifier == Mupass.ToString();
};
AllCRSP.Refresh();
}
The second filter overwrites the first one. If you want to be able to filter by both properties, you need to include both conditions in your predicate:
public void searchMUID()
{
string Mupass = "";
AllCRSP.Filter = obj =>
{
SPFetchCREntity entity = obj as SPFetchCREntity;
return obj != null && entity.SW_Version == SearchMU.ToString() && entity.MU_Identifier == Mupass.ToString();
};
AllCRSP.Refresh();
}
I much prefer using ReactiveList from ReactiveUI and its derived collection. It just works - no need to manualy fire Refresh
public class TweetsListViewModel : ReactiveObject
{
ReactiveList<Tweet> Tweets = new ReactiveList<Tweet>();
IReactiveDerivedList<TweetTileViewModel> TweetTiles;
IReactiveDerivedList<TweetTileViewModel> VisibleTiles;
public TweetsListViewModel()
{
TweetTiles = Tweets.CreateDerivedCollection(
x => new TweetTileViewModel() { Model = x },
x => true,
(x, y) => x.CreatedAt.CompareTo(y.CreatedAt));
VisibleTiles = TweetTiles.CreateDerivedCollection(
x => x,
x => !x.IsHidden);
}
}
If SPFetchCREntity does not implement INotifyPropertyChanged you can create dervied collection with reset argument, which is observable. Every time it ticks, whole list is filtered
This is how i resolved dual filter issue. i got the idea from this link https://code.msdn.microsoft.com/windowsdesktop/CollectionView-Tips-MVVM-d6ebb4a7
public void searchMUID()
{
Muview = (CollectionView)new CollectionViewSource { Source = CRmappings2 }.View; //CRmappings2 is an observable collection and Muview is a public property of collectionview
//FirstCRSP = AllCRSP;
//muview.Filter = null;
Muview.Filter = obj =>
{
SPFetchCREntity entity = obj as SPFetchCREntity;
return obj != null && entity.SW_Version == SearchMU.ToString() && entity.MU_Identifier == Mupass.ToString();
};
Muview.Refresh();
}
Related
I have a list of errors defined as the following:
List<Errors> test1 = new List<Errors>();
public class Errors
{
public int ID {get; set;}
public int Occurrence {get; set;}
//.....
//.....
}
The errors are unique by the combination of the two fields above.
A second list keeps track of whose been assigned to the errors.
List<Tasks> test2 = new List<Tasks>();
public class Tasks
{
public int ID {get; set;}
public int Occurrence {get; set;}
public int EmployeeID {get; set;}
//.....
}
Also made unique by the same two fields. Essentially the tasks are a subset of the errors that have been assigned to someone.
I would like to use a LINQ query (or equivalent) to determine if the composite ID from the List<Errors> exists in List<Tasks>... To be clear it must use both IDS.
I have found the below solution but have not been able to adopt it to a composite key.
`var test2NotInTest1 = test2.Where(t2 => !test1.Any(t1 => t2.Contains(t1)));`
Just need to use and && operator and check both properties instead of one:
var test2NotInTest1 = test2.Where(t2 => !test1.Any(t1 => t1.ID == t2.ID && t1.Occurance == t2.Occurance);
There is a function for that... Except
var test2NotInTest1 = test1.Except(test2);
If you don't have it you will need to create the interface for equal -- something like this:
var test2NotInTest1 = test1.Except(test2, new ErrorsComparer());
class ErrorsComparer : IEqualityComparer<Errors>
{
public bool Equals(Errors x, Errors y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.ID == y.ID && x.Occurrence == y.Occurrence;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Errors e)
{
if (Object.ReferenceEquals(e, null)) return 0;
int hashID = e.ID == null ? 0 : e.ID.GetHashCode();
int hashO = e.Occurrence.GetHashCode();
//Calculate the hash code for the product.
return hashID ^ hashO;
}
}
You were almost there, just add a correct condition to the LINQ expression:
var test2NotInTest1 = listOfErrors.Where(e => !listOfTasks.Any(t => t.ID == e.Id && t.Occurrence == e.Occurrence)).ToList();
For: to determine if the composite ID from the Errors exists in Tasks...
Another approach is to use Enumerable.Join Method
var assignedErrors =
errors.Join(tasks,
error => new { Id = error.Id, Occurrence = error.Occurrence },
task => new { Id = task.Id, Occurrence = task.Occurrence },
(error, task) => error);
For: to determine if the composite ID from the Errors not exists in Tasks..., as in your sample:
var test2NotInTest1 = test2.Where(t2 => !test1.Any(t1 => t2.Contains(t1)));
You can use HashSet to "speed up" search for already assigned errors.
var assignedErrors = tasks.Select(task => (task.Id, task.Occurrence)).ToHashSet();
var notAssignedErrors =
errors.Where(error => assignedErrors.Contains((error.Id, error.Occurrence)) == false)
.ToList();
Or create your own domain specific extension method:
public static IEnumerable<Errors> NotAssignedIn(
this IEnumerable<Errors> errors,
IEnumerable<Tasks> tasks)
{
var assigned = new HashSet<(int Id, int Occurrence)>();
foreach (var task in tasks)
{
assigned.Add((task.Id, task.Occurrence));
}
foreach (var error in errors)
{
if (assigned.Contains((error.Id, error.Occurrence)) == false)
{
yield return error;
}
}
}
Usage:
var notAssignedErrors = errors.NotAssignedIn(tasks);
I'm trying to construct an expression that ultimately results in a query like
SELECT p.*
FROM MyEntity p
WHERE EXISTS(SELECT *
FROM filters
WHERE (filter.type = 1
AND filter.objectid = p.id
AND filter.value = 1
OR filter.type = 1
AND filter.objectid = p.id
AND filter.value = 2))
AND EXISTS(...)
Obviously it won't look exactly like that, but that's the general idea.
I'm using PredicateBuilder to build the query based on the filters passed in, so I have something like this:
var query = context.Set<MyEntity>().AsExpandable();
var predicate = PredicateBuilder.New<MyEntity>(true);
//loop through the group filters. The filters in a group have an or relationship
foreach (FilterGroup group in filters)
{
predicate = predicate.And(
p => context.Set<FilteringValue>().AsExpandable().Any(getFilteringPredicate(p,group ))
);
}
return query.Where(predicate);
And the getFilteringPredicateMethod:
Expression<Func<FilteringValue,bool>> getFilteringPredicate(MyEntity p, FilterGroup filters) {
var fPredicate = PredicateBuilder.New<FilteringValue>(true);
foreach(var filter in filters.FilterList)
{
fPredicate= fPredicate.Or(fv => fv.objectid == p.Id && fv.Type== 1 && fv.value == filter.Value);
}
return fPredicate
}
This seems relatively simple, however I'm getting the error
variable 'p' of type 'Models.MyEntity' referenced from scope '', but it is not defined.
Is there no way to pass the product object into the getFilteringPredicate() method? MyEntity and Filter are not related in Entity Framework.
So... I think I finally got it, you want to relate two expression parameters and build up a composite query (what I mean by the informal definition of "composite" is a subquery having a reference to the main query parameter(s)):
Unfortunately, LinqKit does not support multi-parameter expressions 'AFAIK', which is something that would be a perfect match for your case:
Well, anyway... here it goes. By the way FilteringValues and MyEntities are just two DbSets, I just happen to be using LinqPad to test this out ATM (Questions?):
void Main(string[] args)
{
var entityQuery = MyEntities.AsExpandable();
var filterGroups = GetFilterGroups();
// Initialize with TRUE since no group filter implies Everything matches
var predicate = PredicateBuilder.New<MyEntity>(true);
var filteringValueQuery = FilteringValues.AsExpandable();
foreach (var g in filterGroups)
{
if (!g.FilterList.Any())
{
// If we have no filters in the group, skip
continue;
}
var expressionForGroupFilters = BuildExpressionForGroupFilters(g.FilterList);
predicate = predicate.And(entity => filteringValueQuery.Any(filteringValue => expressionForGroupFilters.Invoke(entity, filteringValue)));
}
entityQuery = entityQuery.Where(predicate);
var data = entityQuery.ToList();
data.Dump();
}
public static Expression<Func<MyEntity, FilteringValue, bool>> BuildExpressionForSingleFilter(Filter groupFilter)
{
var value = groupFilter.Value;
return (entity, filteringValue) =>
filteringValue.Type == 1
&& filteringValue.ObjectId == entity.Id
&& filteringValue.Value == value;
}
public static Expression<Func<MyEntity, FilteringValue, bool>> BuildExpressionForGroupFilters(IReadOnlyCollection<Filter> groupFilters)
{
Expression<Func<MyEntity, FilteringValue, bool>> result = null;
foreach (var groupFilter in groupFilters)
{
var expression = BuildExpressionForSingleFilter(groupFilter);
if (result == null)
{
result = expression;
continue;
}
var tempResult = result.Expand();
result = (entity, filteringValue) => tempResult.Invoke(entity, filteringValue) || expression.Invoke(entity, filteringValue);
}
return result.Expand();
}
public static FilterGroup CreateFilterGroupWithValues(params int[] values)
{
var filterList = values
.Select(x => new Filter { Value = x })
.ToList();
return new FilterGroup { FilterList = filterList };
}
public static IEnumerable<FilterGroup> GetFilterGroups()
{
return new[] {CreateFilterGroupWithValues(0, 2, 4), CreateFilterGroupWithValues(1)};
}
public class Filter
{
public int Value { get; set; }
}
public class FilterGroup
{
public FilterGroup()
{
FilterList = new List<Filter>();
}
public List<Filter> FilterList { get; set; }
}
I was wondering what was the best approach to compare multiple objects that are created and having the state of the objects changed to Inactive (Deleted), while creating history and dependencies.
This also means im comparing past and present objects inside a relational table (MarketCookies).
Id | CookieID | MarketID
The ugly solution i found was calculating how many objects had i changed.
For this purpose lets call the items of the Past: ListP
And the new items: ListF
I divided this method into three steps:
1 - Count both lists;
2 - Find the objects of ListP that are not present in List F and change their state to Inactive and update them;
3 - Create the new Objects and save them.
But this code is very difficult to maintain.. How can i make an easy code to maintain and keep the functionality?
Market Modal:
public class Market()
{
public ICollection<Cookie> Cookies {get; set;}
}
Cookie Modal:
public class Cookie()
{
public int Id {get;set;}
//Foreign Key
public int CookieID {get;set}
//Foreign Key
public int MarketID {get;set;}
}
Code:
public void UpdateMarket (Market Market, int Id)
{
var ListP = MarketCookiesRepository.GetAll()
.Where(x => x.MarketID == Id && Market.State != "Inactive").ToList();
var ListF = Market.Cookies.ToList();
int ListPCount = ListP.Count();
int ListFCount = ListF.Count();
if(ListPCount > ListFCount)
{
ListP.Foreach(x =>
{
var ItemExists = ListF.Where(y => y.Id == x.Id).FirstOrDefault();
if(ItemExists == null)
{
//Delete the Object
}
});
ListF.Foreach(x =>
{
var ItemExists = ListP.Where(y => y.Id == x.Id).FirstOrDefault();
if(ItemExists == null)
{
//Create Object
}
});
}
else if(ListPCount < ListFCount)
{
ListF.Foreach(x =>
{
var ItemExists = ListP.Where(y => y.Id == x.Id).FirstOrDefault();
if(ItemExists == null)
{
//Create Objects
}
});
ListP.Foreach(x =>
{
var ItemExists = ListF.Where(y => y.Id == x.Id).FirstOrDefault();
if(ItemExists == null)
{
//Delete Objects
}
});
}
else if(ListPCount == ListFCount)
{
ListP.Foreach(x =>
{
var ItemExists = ListF.Where(y => y.Id == x.Id).FirstOrDefault();
if(ItemExists == null)
{
//Delete Objects
}
});
ListF.Foreach(x =>
{
var ItemExists = ListP.Where(y => y.Id == x.Id).FirstOrDefault();
if(ItemExists == null)
{
//Create Objects
}
});
}
}
Without a good, minimal, complete code example that clearly illustrates the question, it's hard to know for sure what even a good implementation would look like, never mind "the best". But, based on your description, it seems like the LINQ Except() method would actually serve your needs reasonably well. For example:
public void UpdateMarket (Market Market, int Id)
{
var ListP = MarketCookiesRepository.GetAll()
.Where(x => x.MarketID == Id && Market.State != "Inactive").ToList();
var ListF = Market.Cookies.ToList();
foreach (var item in ListP.Except(ListF))
{
// set to inactive
}
foreach (var item in ListF.Except(ListP))
{
// create new object
}
}
This of course assumes that your objects have overridden Equals() and GetHashCode(). If not, you can provide your own implementation of IEqualityComparer<T> for the above. For example:
// General-purpose equality comparer implementation for convenience.
// Rather than declaring a new class for each time you want an
// IEqualityComparer<T>, just pass this class appropriate delegates
// to define the actual implementation desired.
class GeneralEqualityComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _equals;
private readonly Func<T, int> _getHashCode;
public GeneralEqualityComparer(Func<T, T, bool> equals, Func<T, int> getHashCode)
{
_equals = equals;
_getHashCode = getHashCode;
}
public bool Equals(T t1, T t2)
{
return _equals(t1, t2);
}
public int GetHashCode(T t)
{
return _getHashCode(t);
}
}
Used like this:
public void UpdateMarket (Market Market, int Id)
{
var ListP = MarketCookiesRepository.GetAll()
.Where(x => x.MarketID == Id && Market.State != "Inactive").ToList();
var ListF = Market.Cookies.ToList();
IEqualityComparer<Cookie> comparer = new GeneralEqualityComparer<Cookie>(
(t1, t2) => t1.Id == t2.Id, t => t.Id.GetHashCode());
foreach (var item in ListP.Except(ListF, comparer))
{
// set to inactive
}
foreach (var item in ListF.Except(ListP, comparer))
{
// create new object
}
}
I have the following class:
public class DocumentCompare
{
public string Customer;
public string Filename;
public string Reference;
public DateTime? Date;
public override bool Equals(object obj)
{
if (obj == null)
return false;
DocumentCompare doc = obj as DocumentCompare;
if ((Object)doc == null)
return false;
return (doc.Customer == Customer) && (doc.Date == Date) && (doc.Filename == Filename) && (doc.Reference == Reference);
}
public bool Equals(DocumentCompare doc)
{
if ((object)doc == null)
return false;
return (doc.Customer == Customer) && (doc.Date == Date) && (doc.Filename == Filename) && (doc.Reference == Reference);
}
public override int GetHashCode()
{
return string.Format("{0}_{1}_{2}_{3}",Customer,Filename,Reference,(Date == null ? "" : Date.Value.ToString())).GetHashCode();
}
}
I will be retrieving 2 lists of this class - what I want to do is to compare the two, and get ones that don't exist in both. So if an item exists in x list but not in y, I want to perform an action for the items in this list. If an item exists in y list but not in x, I want to do a different action.
How would I do this? Using LINQ I guess!
EDIT: Performance is not much of an issue - this will only be run once
It sounds like you just want Except:
foreach (var newItem in firstList.Except(secondList))
{
...
}
As an aside:
That's not a terribly nice way of generating a hash code - search for other questions here.
Delegate from Equals(object) to Equals(DocumentCompare) to avoid repetitive logic
Mutable types aren't great candidates for equality comparisons (in particular, one you've used a value as a key in a dictionary, if you change the equality-sensitive components you won't be able to find the key again)
Even if you do want it to be mutable, properties are better for encapsulation than public fields
I would either seal the type or check whether the two objects are exactly the same type, as otherwise you could end up with asymmetric equality
here is the code:
var elementsMissingFromFirstList = firstList.Except(secondList).ToList();
var elementsMissingInSecondList = secondList.Except(firstList).ToList();
now you can perform your actions on these missing elements :)
You can use this method to compare objects of two different Lists. exmp: List and List x and y = DocumentCompare,
public static bool EqualsObject<T>(this T t1, T t2) where T : class
{
var p1 = t1.GetType().Fields();
var p2 = t2.GetType().Fields();
for (int j = 0; j < p1.Length; j++)
{
var x = p1[j].GetValue(t1, null);
var y = p2[j].GetValue(t2, null);
if (x == null && y == null)
continue;
if (x != null && y == null)
return false;
if (x == null)
return false;
if (!x.Equals(y))
{
return false;
}
}
return true;
}
This method will show the difference between these two lists.
public static List<T> DifferentObjects<T>(List<T> t, List<T> t2) where T : class
{
var diff = new List<T>();
if (t != null && t2 != null)
{
foreach (T t1 in t)
{
var state = false;
foreach (T t3 in t2.Where(t3 => EqualsObject(t1,t3)))
{
state = true;
}
if (!state)
{
diff.Add(t1);
}
}
}
return diff;
}
you can use code this way
var t = new List<DocumentCompare>();
var t2 = new List<DocumentCompare>();
t.Add(new DocumentCompare{Customer = "x"});
t.Add(new DocumentCompare{Customer = "y"});
t.Add(new DocumentCompare{Customer = "z"});
t2.Add(new DocumentCompare { Customer = "t" });
t2.Add(new DocumentCompare { Customer = "y" });
t2.Add(new DocumentCompare { Customer = "z" });
var list = DifferentObjects(t, t2);
var list2 = DifferentObjects(t2, t);
you used fields (Customer,FileName etc..) in your class, so that GetType().Fields(); is used in EqualsObject method. if you use property , you should use GetType().Properties(); in EqualsObject method.
Say I have a class that looks something like this:
class SomeClass {
int m_member;
public int Member {
get { return m_member; }
set { m_member = value; }
}
}
And somewhere else, I have a list of type List<SomeClass> list.
If I want to search the list for a particular instance of the class, I can just do
int index = list.IndexOf(someInstance);
But if I want to search the list by Member, I have to do this:
int index = -1;
for (int i = 0; i < list.Count; i++) {
if (list[i].Member == someMember) {
index = i;
break;
}
}
Is there a better way to do this?
int index = list.FindIndex(m => m.Member == someMember);
If you can use Linq
SomeClass aClasss = list.FirstOrDefault(item => item.Member == someMember);
You can have an extended search method(using reflection) for the list like below where property name and search value are input parameters.
public static List<T> SearchList<T>(this List<T> list, string PropertyName, string SearchValue)
{
return list.Select(item =>
new
{
i = item,
Props = item.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
})
.Where(item => item.Props.Any(p =>
{
var val = p.GetValue(item.i, null);
return val != null
&& (p.Name.ToLower() == PropertyName.ToLower() || string.IsNullOrEmpty(PropertyName))
&& (val.ToString().ToLower().Contains(SearchValue.ToLower()) || string.IsNullOrEmpty(SearchValue));
}))
.Select(item => item.i)
.ToList();
}
calling:
List<Employee> employees = new List<Employee>();
var searchedEmployees = data.SortList(serachProperty, searchValue);