Help understand please why that query returns same values but if i use anonymous type it return correct result
//same values
var deviceMessageList1 = _deviceMessageRepository.Fromdevicemessages
.Where(m => m.DeviceId == deviceId).Take(1000).ToList();
//different values
var deviceMessageList2 = _deviceMessageRepository.Fromdevicemessages
.Where(m => m.DeviceId == deviceId).Take(1000).Select(x=> new { Message = x.Message }).ToList();
[]
I've made a few assumptions:
I assume your entity class is called Fromdevicemessage
I assume that Message is a String property
.Select() in LINQ does not influence which items are retrieved. It only influences how the retrieved items are presented.
If you know SQL, you will see that SELECT in SQL works exactly the same (which is why the LINQ method is intentionally called Select, as it works the same, functionally speaking)
It helps if you understand the intention of every method, I'll comment it in:
var deviceMessageList1 =_deviceMessageRepository.Fromdevicemessages
.Where(m => m.DeviceId == deviceId) //Only return the items which have their DevicedId set to [deviceId]
.Take(1000) //Give me the first 1000 items
.ToList() //Make a list from these 1000 items
Notice that you have only specified which rows you want to retrieve. You have not specified how you want the output to be formatted.
By default, you will receive objects of the corresponding entity type Fromdevicemessage.
The list you see at the end is therefore a List<Fromdevicemessage>.
var deviceMessageList1 =_deviceMessageRepository.Fromdevicemessages
.Where(m => m.DeviceId == deviceId) //Only return the items which have their DevicedId set to [deviceId]
.Take(1000) //Give me the first 1000 items
.Select(x => x.Message) //For each retrieved item, instead of the item itself, only give me its Message (= string)
.ToList() //Make a list from these 1000 strings
Notice what the Select statement adds. It basically tells you that you do not want the full Fromdevicemessage object, but only want the Message property. You're basically telling the compiler the following:
For each Fromdevicemessage object that is currently retrieved, render me its Message property.
You were originally working with a collection of Fromdevicemessage objects. But the .Select() statement converted that collection into a collection of String objects.
Simplified, the Select() method converts every object in the source collection, based on your mapping (e.g. x => x.Message), and returns you the list of mapped values.
The list you see at the end is therefore a List<String>.
I cheated a little bit...
In case you hadn't noticed, I changed your Select statement.
Your version:
.Select( x => new { Message = x.Message } )
My version:
.Select( x => x.Message )
Both are valid code, but they work a bit differently.
Your version converts the retrieved items into anonymous objects. The resulting list will therefore be a list of anonymous objects.
My version converts the retrieved items into String objects. The resulting list will therefore be a list of strings.
There are cases where creating an anonymous type is useful. Most commonly, it is useful if you want to return multiple values (e.g. both the Message and Recipient properties).
However, your example only retrieves a single property. In this case, there is no benefit to using anonymous types. Using anonymous types when you want to retrieve a single property makes the code more complex for no good reason or benefit.
You are making yourself responsible for later unwrapping that anonymous type and reading its Message property.
It's easier to simply handle the strings directly, rather than wrapping them in an anonymous type. That means you have one less wrapped layer to worry about.
Update after your comment
Taking a closer look at the image you linked; is your question specifically why the debug values (when you hover over the results like you do in the picture) are different?
What you see in the little popup (before expanding) is essentially the .ToString() output of the variable you're inspecting.
The first example consists of a List<Fromdevicemessage>. Since Fromdevicemessage is a custom class you've built (and I assume you did not override its .ToString() method, the default ouput will be the name of the class, not its contents.
That's just how it works. If you override the .ToString() method in your Fromdevicemessage class, then you can change what it looks like.
public override string ToString()
{
return $"Message : {this.Message}";
}
In the second example, you are dealing with a List of anonymous types. Anonymous types have a custom .ToString() method, which already shows you the content of the object rather than its classname (since anonymous objects have no classname, at least as far as a developer can see).
Both the queries are same except in second query you are using anonymous type.
first query will return original object with all the properties in that object and second query will just return message as you are using anonymous type.
To better understand this is like
//first query
select Top 1000 * from Fromdevicemessages
//Second query
select Top 1000 Message from Fromdevicemessages
Related
I have an IEnumerable of objects which I need to turn into a filtered dictionary. The key of the dictionary must be the object's name and the value must be one of its properties. I do so using LINQ's ToString method:
// dataPoints is of type IEnumerable
var filteredDictionary = dataPoints.Where(d => d.TypeName == typeNameOfInterest).ToDictionary(d => d.Name, d => d.Identifier)
I eventually turn the dictionary into a string as follows:
string.Join(Environment.NewLine, filteredDictionary.Select(d => $"{d.Key} : {d.Value};").ToArray()))
This works and the order of the elements in the string is the same as the order in the IEnumerable. I think that is what the documentation means by stating the following about the returned dictionary
The values within each group are in the same order as in source
Now, I need to get the first element from the dictionary. By first I mean the first one listed in the original IEnumerable. How would I need to do this? Can I rely on LINQ's first method to do so and be sure that it is the correct one? Would I need to construct a SortedDictionary before getting the first element?
I'm using the .NET Framework 4.7.2 and I never modify the content of the dictionary that I receive from ToDictionary.
I have a list of anonymous objects, that each anonymous object has the same members, and I create this list by something like this :
var listWorthies = balanceWorthies.Select(w => new
{
OwnerName = w.OwnerOnInquery,
OwnerDocDate = w.OwnerDocDate,
}).ToList();
Now I just wanted to convert the OwnerDocDate member of each dynamic object.
something like this :
var listWorthies = balanceWorthies.Select(w => new
{
OwnerName = w.OwnerOnInquery,
OwnerDocDate = ConvertDate(w.OwnerDocDate),
}).ToList();
gives me the error
LINQ to Entities does not recognize the method 'System.String ConvertDate(System.DateTime)' method, and this method cannot be translated into a store expression.
after creating the list, I tried somethings like these ones too :
foreach (dynamic Worthy in listWorthies)
{
DateTime OwnerDocDate_2 = ConvertDate(Worthy.OwnerDocDate);
Worthy.AddProperty(OwnerDocDate_2);
}
but it gives me this error :
'<>f__AnonymousType8<string,string,System.DateTime,System.DateTime,System.Guid,string>' does not contain a definition for 'AddProperty'
UPDATE
the output of function ConvertDate is String, and I want to change the type of OwnerDocDate from datetime to string.
how can I solve this?
You forgot to tell us that balanceWorthies is an IQueryable<...>, not an IEnumerable<...>.
To understand why this matters, you must understand the difference between an IQueryable<...>, and an IEnumerable<...>.
IEnumerable
An object of a class that implements IEnumerable<...>, represents a sequence. You can get the first element, and once you've got an element, you can get the next element, as long as there are elements.
At its lowest level this is done using methode GetEnumerator() / MoveNext() / Current:
IEnumerable<Cusotmer> customers = ...
IEnumerator<Customer> enumerator = customers.GetEnumerator();
while (enumerator.MoveNext())
{
// There is still a Customer in the sequence:
Customer customer = enumerator.Current;
ProcessCustomer(customer);
}
foreach will deep inside do this.
If you look at the LINQ methods, you will see that there are two groups of methods: the ones that return IEnumerable<...> and the others. The first group won't enumerate the sequence. We say that they use lazy-execution or deferred-execution. In the description of these LINQ methods, you'll find this term in the remarks section.
Concatenating methods of this group isn't expensive: the query is not executed, only the Enumerator is adjusted.
The LINQ methods that return something else than IEnumerble<...> will execute the sequence. Deep inside GetEnumerator / MoveNext / Current is called to access the elements of the source sequence one by one.
IQueryable
An object of a class that implements IQueryable<...> doesn't represent an enumerable sequence, it represents the potential to fetch an enumerable sequence.
To do this, the class holds an Expression and a Provider. The Expression holds what data must be fetched in some generic format. The Provider knows where the data must be fetched (usually a Database Management System) and what language is used to communicate with this DBMS (usually SQL).
When you ask the IQueryable to get the enumerator, the Expression is sent to the Provider, who will translate the Expression into SQL and fetch the data at the DBMS. The fetched data is presented as an IEnumerator<...>. The caller can use MoveNext() / Current to access the fetched elements one by one.
Back to your question
The Provider doesn't know your own methods. Hence it doesn't know how to translate them into SQL. In fact, there are several standard LINQ methods that are not supported by entity framework. See Supported and unsupported LINQ methods
Your compiler doesn't know how smart your Provider is, so he can't complain. You'll get the error at runtime.
The easiest way to solve your problem is by transferring the data to your local process and let your local process execute the methods as if it was an IEnumerable<...>.
This is done using the method Enumerable.AsEnumerable. As transferring data is expensive, it is wise to limit the data being transferred to a minimum before you call AsEnumerable. So first do all your Where, (Group-)Join, etc. everything that limits the amount of transferred data.
var listWorthies = balanceWorthies.Select(w => new
{
OwnerName = w.OwnerOnInquery,
OwnerDocDate = w.OwnerDocDate,
})
// OwnerDocDate has the type of balanceWorthy.OwnerDocDate
// move the data to local process, so you can ConvertDate
.AsEnumerable()
// now you can call your own methods:
.Select(fetchedItem => new
{
OwnerName = fetchedItem.OwnderName,
OwnerDocDate = ConvertDate(fetchedItem.OwnerDocDate),
});
Database management systems are extremely optimized in selecting data. It seems that ConvertDate will only translate the data into a different format. So you won't lose a lot of efficiencies.
If in other cases the method will change the amount of selected data, try to change the expression such that the DBMS can handle it, especially if it is before a Where. If the DBMS must execute your code, and you can't translate the LINQ into something that your provider supports, you'll have to write an extension method that changes the Expression. How to do that is something for a different question.
I have some function (X) which return IQueryable with "OrderBy(x => x.Name)".
I want to use X function in new code, but in this code there is parameter which determine the order (asc/desc).
I prefer not to change (X) since it used in multiple places already.
there is option to get X(), then cancel it's "OrderBy", and apply new order?
(now it throws exception, since it is like Y.OrderBy(a => a.Name).OrderByDescending(a => a.Name))
"A column has been specified more than once in the order by list. Columns in the order by list must be unique.\r\nStatement(s) could not be prepared."
use
public void x(string order = string.empty)
{
Y.OrderBy(a => a.Name);
if (order == "desc")
{
Y = Y.Reverse();
}
}
I've tried to wiggle Expression object of IOrderedQueryable that your method is actually returning (am I wrong?) but so far no luck, and I can't see the option to manipulate System.Linq.Expression or System.Linq.EnumerableQuery easy enough to use it instead of changing X() method.
IMHO, you should choose from:
create somes kind of wrapper method using the Reverse() (#Eric Lizotte answer) or OrderByDescending() - it will be less time consuming I guess but for grouping, filtering etc. you will have to create brand new function.
remove OrderBy() from X() function body, and modify your old code - returning non-ordered result will give you more flexibility and opportunity to do what you want to do with the result via linq expressions in each scenario that you'll came across.
Can you clarify for me if you're talking about "function" you have in mind a sql function that is mapped via ORM (eg. Entity Framework) in your application or just a ordinary method which is using your custom provider to return IQueryable?
Can someone explain me this code, especially I'm not sure how generic function as parameter works:
result.Notes= orderInfo.Notes.SafeConvert(x => (Communication.OrderNotes)x);
public static TOut[] SafeConvert<TIn, TOut>(
this TIn[] input,
Func<TIn, TOut> converter)
{
if (input == null)
{
return null;
}
return input
.Where(i => i != null)
.Select(converter)
.ToArray();
}
SafeConvert is a generic extension method. The first parameter (an array of the generic type TIn) is implicitly added when the method is invoked on an array of some type (in this case maybe a note?). The method also requires an function as a parameter. This function must take an instance of the type TIn and return a TOut instance. So, you'd invoke this method on an array of some type, supply a lambda expression or a delegate function, and it will return an array of whatever type your supplied function returns. It does this by using Linq to filter out nulls, run each item in the array through the method, then return the enumeration of those items as an array.
In the implementation you've given, it takes the "Notes" of "orderInfo" and explicitly casts them to "CommunicationOrderNotes."
Here's another way you could invoke the method.
var decimals = new [] {5, 3, 2, 1}.SafeConvert(someInt => (decimal) someInt);
This is what's known as an extension method. It's a static function that allows you to "add" methods to types without modifying the original code. It's somewhat analogous to the Decorator Pattern but there's controversy about whether it's actually an implementation of that particular pattern.
"Under the hood," at least, extension methods are just "syntactic sugar" for calling a static method, but you can call them as if they were an instance method of the extended object (in this case, arrays).
The <TIn, TOut> part means that TIn and TOut are some type you haven't specified yet (but that you intend to specify what they actually are when you go to use the class). To understand the purpose of this, think of a Linked List - really, the implementation of a Linked List of integers isn't any different than the code for a Linked List of strings, so you'd like it to be the case that you can create a single class and specify later that you want a list of integers or a list of strings or whatever. You definitely would not want to have to create an implementation for every single possible type of object - that would require a massive amount of redundant code.
Now, for the LINQ query:
return input
.Where(i => i != null)
.Select(converter)
.ToArray();
LINQ (Language Integrated Query) is a mechanism for querying different types of collections using a single syntax. You can use it to query .NET collections (like they're doing here), XML documents, or databases, for example.
LINQ Queries take an anonymous function of some kind and apply the operator to the collection in some way (see below).
Going through this query;
.Where(i => i != null)
As the name suggests, Where applies a filter. When applied to a collection, it returns a second collection with all of the elements of the first collection that match the filter condition. The
i => i != null
bit is the anonymous function that acts as a filter. Basically, what this is saying is "give me a collection with all of the members of the array that aren't null."
The Select method applies a transform to every element of the collection and returns the result as a second collection. In this case, you apply whatever transformation you passed in as an argument to the method.
It might sound slightly odd to think of code as data, but this is actually very routine in some other languages like F#, Lisp, and Scala. ("Under the hood", C# is implementing this behavior in an object-oriented way, but the effect is the same).
The basic idea of this function, then, is that it converts an array of one type to an array of a second type, filtering out all of the null references.
Suppose we have a class Foo which has an Int32 Field Bar and you want to sort the collection of the Foo objects by the Bar Value. One way is to implement IComparable's CompareTo() method, but it can also be done using Language Integrated Query (LINQ) like this
List<Foo> foos = new List<Foo>();
// assign some values here
var sortedFoos = foos.OrderBy(f => f.Bar);
now in sortedFoos we have foos collection which is sorted. But if you use System.Diagnostics.StopWatch object to measure the time it took OrderBy() to sort the collection is always 0 milliseconds. But whenever you print sortedFoos collection it's obviously sorted. How is that possible. It takes literary no time to sort collection but after method execution the collection is sorted ? Can somebody explain to me how that works ? And also one thing. Suppose after sorting foos collection I added another element to it. now whenever I print out the collection the the element I added should be in the end right ? WRONG ! The foos collection will be sorted like, the element I added was the part of foos collection even if I add that element to foos after sorting. I don't quit understand how any of that work so can anybody make it clear for me ?!
Almost all LINQ methods use lazy evaluation - they don't immediately do anything, but they set up the query to do the right thing when you ask for the data.
OrderBy follows this model too - although it's less lazy than methods like Where and Select. When you ask for the first result from the result of OrderBy, it will read all the data from the source, sort all of it, and then return the first element. Compare this to Select for example, where asking for the first element from the projection only asks for the first element from the source.
If you're interested in how LINQ to Objects works behind the scenes, you might want to read my Edulinq blog series - a complete reimplementation of LINQ to Objects, with a blog post describing each method's behaviour and implementation.
(In my own implementation of OrderBy, I actually only sort lazily - I use a quick sort and sort "just enough" to return the next element. This can make things like largeCollection.OrderBy(...).First() a lot quicker.)
LINQ believe in deferred execution. This means the expression will only be evaluated when you started iterating or accessing the result.
The OrderBy extension uses the deault IComparer for the type it is working on, unless an alternative is passed via the appropriate overload.
The sorting work is defered until the IOrderedEnumerable<T> returned by your statement is first accessed. If you place the Stopwatch around that first access, you'll see how long sorting takes.
This makes a lot of sense, since your statement could be formed from multiple calls that return IOrderedEnumerables. As the ordering calls are chained, they fluently extend the result, allowing the finally returned IOrderedEnumerable to perform the sorting in the most expedient way possible. This is probably achieved by chaining all the IComparer calls and sorting once. A greedy implementation would have to wastefully sort multiple times.
For instance, consider
class MadeUp
{
public int A;
public DateTime B;
public string C;
public Guid D;
}
var verySorted = madeUps.OrderBy(m => m.A)
.ThenBy(m => m.B)
.ThenByDescending(m => m.C)
.ThenBy(m => m.D);
If verySorted was evaluated greedily, then every property in the sequence would be evaluated and the sequence would be reordered 4 times. Because the linq implementation of IOrderedEnumerable deferes sorting until enumeration, it is able to optimise the process.
The IComparers for A, B, C and D can be combined into a composite delegate, something like this simplified representation,
int result
result = comparerA(A, B);
if (result == 0)
{
result = comparerB(A, B);
if (result == 0)
{
result = comparerC(A, B);
if (result == 0)
{
result = comparerD(A, B);
}
}
}
return result;
the composite delegate is then used to sort the sequence once.
You have to add the ToList() to get a new collection. If you do't the OrderBy will be called when you start iterating on sortedFoos.
List<Foo> foos = new List<Foo>();
// assign some values here
var sortedFoos = foos.OrderBy(f => f.Bar).ToList();