I am having a hard time grouping a dbset (EntityFramework) by two fields and sending that output to a strongly typed view.
When I use an anonymous type for the composite key I get the right output. A list containing one item and that item in turn has two or more grouping items.
Now if I use a class instead I get a list of two items and in turn each item has one grouping item.
var output = context.Transfers.GroupBy(t=> new { t.TNumber, t.Type}).ToList();
var output2 = context.Transfers.AsEnumerable()
.GroupBy(t => new OTSpecs(t.TNumber, t.Type)).ToList();
OTSpecs is just a simple class, with those public fields and a parameter constructor.
I need to add the AsEnumerable() otherwise I get a System.NotSupportedException Only parameterless constructors and initializers are supported in LINQ to Entities
Also because I need to define the model in the view like this
#model IEnumerable<IGrouping<OTSpecs, Transfer>>
unless of course it is possible to replace OTSpecs in that line with the anonymous type. But I don't know how.
My question is why those lines of code produce a different output?
Is it possible to define the model in the view replacing the OTSpecs for a anonymous type?
Anonymous types implement equality comparison which compares all their properties. So when you are using anonymous type as a key, linq is able to identify that two key objects are same and should be grouped together.
Your custom object, I suspect, does not implement that stuff, so for it just general object comparison is used, which just compares references. Two key objects have difference references - thus different groups.
To fix this, you may need to either pass in equality comparer, or implement Equals in your class OTSpecs.
Related
As far as I'm aware, there isn't a reliable, documented way to get anonymous type properties in the order that they're declared in a source file which causes me to wonder if I use EF core's HasIndex thus:
modelBuilder.Entity<T>(entity => entity.HasIndex(e => new { e.Z, e.A }) )
..is it certain that the index will be created in column order Z,A ?
I'm less concerned about the params string overload form:
modelBuilder.Entity<T>(entity => entity.HasIndex("Z", "A") )
..because I imagine it would be logical for the array element order to dictate the index column order.
I'm struggling to use this form, however, without hardcoded strings because the DbSet<X> is defined thus:
public virtual DbSet<X> X {get;set;}
..rather than the plural Xs (not my rule, but I'm stuck with it), so trying to use HasIndex(nameof(X.Z), nameof(X.A)) is an error because the nearest accessible X is a collection of X, rather than type X, and hence doesn't have the properties I want to nameof
The closest I've been able to come to work around this issue is to instantiate an X:
modelBuilder.Entity<SessionChargingProfileLog>(entity =>
{
var x = new X(0, 0, "");
entity.HasIndex(nameof(x.Z), nameof(x.A)).IsClustered().IncludeProperties(nameof(x.B));
});
..which is a bit..
So if it could be concretely confirmed that "yes, the HasIndex(e => new { e.Z, e.A }) will definitely create the index as Z, A" it'd be be marvellous; I'd test it, but I don't think "try it and observe if it's right in this case" means that it guarantees it will always work out, versus a "yes, it'll work because.."
As far as I'm aware, there isn't a reliable, documented way to get anonymous type properties in the order that they're declared in a source file
You are missing the fact that here you are not dealing with anonymous type at runtime via reflection, but with compile time generated expression tree representing anonymous type instantiation. The body of the lambda is NewExpression (not MemberInit as it looks syntactically), which is a constructor call with Arguments containing the defining expressions in the order you specify them and also mapped to Members which is specifically made for anonymous types:
The Members property provides a mapping between the constructor arguments and the type members that correspond to those values. In the case of the construction of an anonymous type, this property maps the constructor arguments to the properties that are exposed by the anonymous type. This mapping information is important because the fields that are initialized by the construction of an anonymous type, or the properties that access those fields, are not discoverable through the Constructor or Arguments properties of a NewExpression node.
What about the order, the documentation for Anonymous Types says:
If two or more anonymous object initializers in an assembly specify a sequence of properties that are in the same order and that have the same names and types, the compiler treats the objects as instances of the same type. They share the same compiler-generated type information.
So since the order of the initialization is part of the anonymous type identity, then it should be preserved by the complier, and in turn reflected in the compiler generated lambda expression.
Yes, EF creates index in the same order as you defined, exactly.
Because the order of columns in index is so important in relational databases and all search scenarios are in order of columns for seek indexes (when build the execution plan).
As you know when change the order of columns for specific index you should rebuild that index for create based on new order.
I use nhibernate mapping by code, I want to make this expression dynamicllay (with a nested object)
I have a class event that has a relation many to one with Event state/and I want to grouping by code in the table EventState
var grouping = query.GroupBy(x => x.EventState.Code)
It works for me with a simple property, here is my code:
var arg = Expression.Parameter(type, categoryColumnName);
var bodyy = Expression.Convert(Expression.Property(arg, categoryColumnName), typeof (object));
var lambdaGroupBy = Expression.Lambda<Func<Operation, object>>(bodyy, arg);
var keySelector = lambdaGroupBy.Compile();
var grouping = query.GroupBy(keySelector);
return grouping.Select(a => new PieChartObject { Category = a.Key.ToString(), Value = a.Count().ToString() }).ToList();
But I can't do it with nested object.
GroupBy will partition your query by what you provide as key selector. To determine whether two items in your query have the same key, it uses the default comparer of the given type. For object, this is uses the Equals and GetHashCode methods which in turn for strings mean that the contents of the strings are identical. If you use a class, by default the reference identity is used, so I think that GroupBy isn't doing anything in your case because the keys you provided are not identical, even though they may have the same values.
So there are two valid solutions: You can either override Equals and GetHashCode in your nested object class, or you can provide a custom key comparer to GroupBy, if you want this behavior only for this particular query. But I guess, as you want to be generic, implementing Equals and GetHashCode would be a better option. The only exception is of course when you cannot do this, e.g. because it is a compiler-generated class. In that case, there is few things you can do about that.
Out of curiosity: What comparer is used when sorting a bunch of objects using the following extension method?
OrderBy(x=> x)
Background: I have to check wether two ISet< T > instances contain the same elements and considered to use the
bool setsEqual = MySet.SequenceEqual(OtherSet);
method. As the order of those elements contained in the sets are not defined and may differ, a SequenceEqual would fail in those cases where the internal order is not the same. So i would have to explictly define an order. As the order algo for itself is completely irrelevant as long as it´s stable, i just used an "Identity" lambda expression:
bool setsEqual = MySet.OrderBy(x => x).SequenceEqual(OtherSet.OrderBy(x => x);
But what does "Compare the objects themselves" mean to the code? As this OrderBy extension method is a generic one, there must be a default compare algo in place that is able to sort objects without knowing anything more about it, and that would mean a comparison for sorting had to be delegated to the type of the set elements itself. Is there an interface that the elements´ type would have to support, or is there a default comparer (may be comparing internal memory addresses of objects) in place?
To answer the question of sorting: sorting uses IComparable<T> or IComperable if that isn't implemented. The IComperable interfaces force you to implement a int CompareTo(object) method (or int CompareTo(T) method if you used the typed version).
The order of your elements is determined by the sign of the int. The value returned is interpreted as follows:
0: the two objects are equivalent (i.e. the same)
-1: the compared object precedes this object (i.e. comes before this object)
1: the compared object follows this object (i.e. comes after this object)
The actual value is ignored, the sign is all that matters. If you implement your own IComparable interface, you have to choose the semantics for sort order.
Many objects already implement IComparable already, like all your numbers, strings, etc. You'll need to implement it explicitly if you need to sort objects you've created yourself. It's not a bad practice if you intend those objects to be displayed in a list on screen at all.
As to your specific case, where you just need to determine if a set and another IEnumerable are equivalent, then you would use the ISet<T>.SetEquals(IEnumerable<T>) method which is implemented in the standard library set implementations. Sets, by definition, only guarantee the values are unique, so as long as the number of elements are the same, you only need to detect that all the elements in one IEnumerable can be found in the set.
The method used the IComparable<T>-or the IComparable-interface depending on which of both are implemented. If none is implemented the order is arbitrary.
However you won´t need to order you instances before comparing the sets. Simply loop one set and check if all of its elements are contained in the other set. Or use this:
var areEqual = firstSet.All(x => secondSet.Contains(x)) && secondSet.All(x => firstSet.Contains(x));
Or even simpler:
var areEqual = !firstSet.Except(secondSet).Any() && !secondSet.Except(firstSet).Any();
Both ways perform much faster than your appraoch as the iteration of elements stops when the first element is found that does not fit. Using OrderBy you´d loop all elements, regardless if there was already a mismatch.
Unlike for equality, there's no 'default' comparer for objects in general.
It seems that Comparer<TKey>.Default always returns a comparer, for any type TKey. If no sensible comparison method can be determined, you get an exception, but only once the comparer is used.
At least one object must implement IComparable.
Does anyone know of any naming convention rules/guidelines that dictate when to use a "To" prefix (myVariable.ToList()), an "As" prefix (myVariable.AsEnumerable()), or a "Get" prefix (myVariable.GetHashCode())?
I assume there's no convention, so just use what fits best to what you're doing.
"To" creates something new/ converts it
"As" is just a "different view" on the same f.e. by using iterators
"Get" is a getter for everything else
My understanding/conventions:
"To" performs a conversion; A new object is created in memory, based on the data inherent in your source.
"As" performs a cast; The same reference passed in is returned behind the "mask" of a different type.
"Get" performs pretty much anything else that takes in a source and whose primary product is a transformed result. Gets can perform a calculation, return a child, retrieve data from a store, instantiate objects from a default state, etc. Not all such methods have to be named "Get", but most methods intended to calculate, instantiate, project, or otherwise transform, and then return the product as their primary purpose are "getters".
When myObj is not related to List, prefix "To" to convert.
When myObj is a subclass of Enumerable, prefix "As" to give it as Enumerable
When myObj is not related to List, but it composes / can compose List use "Get" prefix
If you're using Entity Framework for CRUD operations on a database, then using .ToList() will have your query be executed right there, as opposed to using AsEnumerable() which will use deferred execution until you actually try to access a record.
That's one that I thought of right off the top of my head.
As is a reinterpretation of existing data. AsEnumerable does nothing. It is implemented as return input;.
To implies a conversion.
Get does not imply any of the former.
You will find valid deviations from these rules. They are not set in stone.
I would say that To vs As has more to do with differences like class vs interface
i e you are saying AsEnumerable when you really want to return something that implements interface.
ToList on opposite returns new object which is representation of current state of current object, ie ToDictionary just another way of representing same data.
Third ones Get methods returns some properties of the object OR something about part of it's state and not the full state.
i have list of objects i need to sort the list based on object's property1 and i need to sort again the resultant list with object's property2 without loosing the grouping done in first sorting ....
for ex:
obj has 2 property name and location
i need to have a final list of objects which has been sorted with region and objects of same region should be sorted by name...
(Assuming you don't have LINQ available to you, which makes this trivial.)
If you look in MiscUtil, you'll find two useful classes: ProjectionComparer and LinkedComparer (IIRC).
ProjectionComparer basically implements the LINQ "order by" concept - you specify how to convert a source element to a key value, and the comparer will order by those key values.
LinkedComparer takes two comparers and returns a new comparer which uses the "primary" comparer first, and the "secondary" comparer if values are equal with respect to the primary one.
Create two projection comparers (one for each property) and then a linked comparer with the two of them, then pass that to List<T>.Sort. Let me know if you need a full code sample, but it would be something like (using C# 3):
var comparer = new LinkedComparer<Foo>
(ProjectionComparer<Foo>.Create(x => x.FirstProperty),
ProjectionComparer<Foo>.Create(x => x.SecondProperty));
(In C# 2 you could use anonymous methods, they'd just be a bit more long-winded.)
Sounds like you want to use LINQ's orderby and thenby syntax.
A List has a Sort method which takes a Comparision delegate as an argument.
There are also overloads where you can pass in your own comparer.
So, you can write a class which implements IComparer. Then, in the implementation of this class, you write the code where you compare the 2 objects on the properties you want.