TSQL OrderBy vs LINQ OrderBy Madness for UniqueIdentifier - c#

After hours of trying to figure out why a piece of code is out of sync i came to the realization that TSQL OrderBy differs greatly from Linq OrderBy for strings. So naturally I had to find a way to make sure a statement from tsql returns the same order as linq so I used a uniqueidentifier(guid) as my primary, however that seems to be wacked.
Here is the order using Linq (using the Guid(UniqueID) type for the property)
var listings = validListings.Select(x => x.TempListing)
.OrderBy(x => x.UniqueID)
.ToList();
It seems TSQL uses the binary value of the uniqueidentifier to compare while LINQ uses the string value even though the row is GUID
LINQ RESULTS (Printed) (first few)
00460400-a41d-465d-83c5-225f697e7bb5
015bef8d-5fa3-4c03-8d05-bfecf74b36b9
0202b433-4748-4660-97a1-94d119209aa6
03f34eb0-45cd-4586-b7d2-6e337b441c43
05e41d20-be24-4f4f-b098-574744dd84f0
0767e5d5-afba-49ab-a047-c9f509c80d3a
08f87ba1-8aa8-48a6-8f98-c3b4c6511b76
0b4157c4-7bdc-4e98-a00c-9259af754844
0bd194d0-fb66-4a69-9718-2128594ff9b0
0cda256a-7632-47de-b867-a2bc46382881
0d36f81a-ca37-446e-a325-87b46ef5b8d3
0d89fd26-4204-4d0a-b187-73a36536a848
0e345ca9-3d5d-43ed-aa75-fbd356f94535
0e767557-87ea-4c31-9f54-75d354a87d0f
0f62fc97-85b0-4611-b3e5-0c5ae4f12a18
1020d776-9810-4122-a9ef-3c527f21970c
TSQL FIRST FEW
9C5231CE-01DE-4A20-A4C9-001AD0D28512
3D52B47C-B29C-44A8-99F9-00AA660610A8
FDA7B67D-AEDB-4644-96E4-0147A0EEC29D
C8C7B677-76EB-41D3-B11C-020B9047EB00
487FF542-599B-42D4-BCE3-02C5D569E509
BDAA48DB-60AF-4A36-AFDB-02FA706EE87F
2CD9D59C-C2B5-433C-9FD1-0444F0384BB3
D44695A3-6FEF-4842-BFCB-048C110FA178
28FF051C-38A7-424F-B657-0698452DFE36
D9320EC6-64CD-4C26-8C5C-088C04E22AD7
D9F7FDC1-16D6-4C3A-B117-0908A234DF95
7DB09D09-F10B-4F33-9390-09211F9B2958
D970EE98-B575-4E73-BBAC-0981D6DC1682
9B05CDD9-2D85-486B-BC6B-0BA7E44F6021
539D22ED-FF2A-4376-A650-0BFE184C0E26
0F62FC97-85B0-4611-B3E5-0C5AE4F12A18
5D8EF134-0DC2-4B32-9F02-0C65940C1BCF
How can I make them both return the same result?

As you have discovered, C# (System.Guid) and SQL Server use different algorithms to sort GUIDs.
If you want SQL Server to sort GUIDs the way System.Guid does, then convert it to VARCHAR.
If you want to sort Guids in C# the way SQL does, convert the Guid values to System.Data.SqlGuid:
var listings = validListings.Select(x =>x.TempListing)
.OrderBy(x=> new SqlGuid(x.UniqueID)).ToList();
That said, GUID is not an appropriate data type for a sortable column - I would switch to an IDENTITY column if possible.

Related

Generate IN statement for decimal values with Oracle

I'm having trouble getting LINQ to generate an IN statement. I have a function that looks like the one below, taking as input a list of long representing the primary keys to find. Using the contains methods ends up generating a query of composite OR statements. We're running against an Oracle database. We're using the newest version of LINQ/EF. QueryableDbSet is a DbSet. The PrimaryKey property is a decimal value and is the primary integer identifier for the object in Oracle.
List<long> GetList(List<long> ids)
{
List<decimal> dIds = ids.Select(x => (decimal)x);
var query = from c in QueryableDbSet
where dIds.Contains(c.PrimaryKey)
select (long)c;
return query.ToList();
}
The above code will generate composite OR statements. Does any one know how to get LINQ to generate the faster IN statements? Thanks.
EDIT: Doing some more research it appears that Oracle actually converts IN statements to OR chains, so maybe this is an exercise in futility. Can anyone confirm or deny this?
Also, I'm aware that the above function is completely pointless/redundant. My real use case is more complicated and involves other conditionals in the where clause.

Retrieve only the first row from a table in Entity Framework

Background:
Entity Framework 4, with SQL Server 2008
Problem:
I have a table Order. Each row has a column Timestamp.
The user can choose some time in past and I need to get the Order closest to the specified time, but that had occurred before the specified time. In other words, the last order before the specified time.
For example, if I have orders
2008-01-12
2009-04-17
2009-09-24
2010-11-02
2010-12-01
2011-05-16
and choose a date 2010-07-22, I should get the 2009-09-24 order, because that's the last order before the specified date.
var query = (from oData in db.OrderDatas
where oData.Timestamp <= userTime
orderby oData.Timestamp ascending
select oData).Last();
This is closest to what I am trying. However, I am not sure how exactly does the Last operator work when translated to SQL, if it's translated at all.
Question:
Will this query fetch all data (earlier than userTime) and then take the last element, or will it be translated so that only one element will be returned from the database? My table can hold very large number of rows (100000+) so performance is an issue here.
Also, how would one retrieve the closest time in the database (not necessarily the earlier time)? In the example of 2010-07-22, one would get 2010-11-02, because it is closer to the date specified than 2009-09-24.
In general, if you're concerned about how LINQ behaves, you should check what does happen with the SQL. If you haven't worked out how to see how your LINQ queries are turned into SQL, that should be the very next thing you do.
As you noted in your comment, Last() isn't supported by LINQ to SQL so the same may be true for EF. Fortunately, it's easy to use First() instead:
var query = (from oData in db.OrderDatas
where oData.Timestamp <= userTime
orderby oData.Timestamp descending
select oData).First();
Try using:
var query = (from oData in db.OrderDatas
where oData.Timestamp <= userTime
orderby oData.Timestamp descending
select oData).Take(1);
It's the equivalent of TOP 1
Question:
Will this query fetch all data (earlier than userTime) and then take
the last element, or will it be translated so that only one element
will be returned from the database? My table can hold very large
number of rows (100000+) so performance is an issue here.
In this case, using the first() approach, the query will be executed immediately and it will optimized in such a way that it will ony retrieve 1 record. Most probably a top(1) select. You really need to check the genereated sql with a sql profilihg tool or by using the log of the datacontext. Or you can use linqpad. linq-2-sql can lead to N+1 queries if not used the proper way. This behaviour is quite predictable but in the beginning you really have to be aware.

Create LINQ expression with two aggregate operators [duplicate]

This rather simple SQL query is proving to be quite perplexing when attempting it from LINQ.
I have a SQL table Plant with column ZoneMin.
I want to find the minimum and maximum of the values in the column.
The answer in T-SQL is quite simple:
SELECT MIN(ZoneMin), MAX(ZoneMin) FROM Plant
What's a LINQ query that could get me to this (or some similar) SQL?
I've made various attempts at .Aggregate() and .GroupBy() with no luck. I've also looked at several SO questions that seem similar.
This could be simply achieved with methods applied to a resulting array, but I shouldn't need to transport a value from every SQL row when it's so simple in T-SQL.
To achieve the same performance as your original query, you'll need to use grouping (by a constant to minimize impact, e.g. 0), so that you can refer to the same set of records twice in the same query. Using the table name causes a new query to be produced on each reference. Try the following:
(from plant in db.Plants
group plant by 0 into plants
select new { Min = plants.Min(p => p.ZoneMin), Max = plants.Max(p => p.ZoneMin) }
).Single()
This produces the following query:
SELECT MIN(plants.ZoneMin), MAX(plants.ZoneMin)
FROM (SELECT 0 AS Grp, ZoneMin FROM Plants) AS plants
GROUP BY plants.Grp
And after the optimizer is done with it, it spits out something equivalent to your query, at least according to SQL Server Management Studio.

How do I implement a search feature with Entity Framework?

I have a blog application that models a database using Entity Framework. The problem with this blog is that it has become difficult to find things I'm looking for. It needs a search function, but I'm not sure how to implement this with SQL and/or LINQ to Entities.
Right now I am searching my database with this LINQ query but it seems like it should be better.
public IEnumerable<BlogPost> SearchBlogPosts(string query, int page, int itemsPerPage)
{
var result = _dataContext.BlogPosts
.Where(BlogPostContains(query))
.OrderByDescending(x => x.PostedDate)
.Skip((page - 1) * itemsPerPage)
.Take(itemsPerPage),
return result;
}
private Func<BlogPost, bool> BlogPostContains(string query)
{
return x => x.Title.Contains(query) || x.Body.Contains(query) || x.Author.Contains(query);
}
One big problem with this is that the search is case sensitive.
Question 1) Is there a better way to do searching with LINQ to Entities?
Question 2) What about with just plain SQL? How would I write a search stored procedure in SQL Server so that I can map and use that in EF instead of LINQ?
I just want a case-insensitive search that is performed in the database so as to maintain good performance.
Thanks in advance.
The standard approach for this would be a SQL fulltext search. You will have to enable fulltext on the DB, designate column(s) to be fulltext indexed and then will then be able to use SQL Contains queries using these columns.
Fulltext search queries are currently not supported by Linq to Entities - you will have to resort to standard SQL queries for this. You can use ExecuteStoreQuery() to at least map the search results to typed result.
The default collation of SQL Server is case-insensitive which means that a where clause like this (which is what LINQ to Entities would create out of Contains)...
where Name like '%JOHN%'
...should find "john Wayne". I believe that your query is not executed on the server but actually with LINQ to Objects in memory - and there the search is case sensitive. It's LINQ to Objects because you are not returning an Expression from your BlogPostContains. The signature should be:
private Expression<Func<BlogPost, bool>> BlogPostContains(string query)
If your are only returning Func<BlogPost, bool> you are working with the IEnumerable (and not the IQueryable) overload of the Where extension method which in turn causes the whole BlogPosts table loaded first into memory. Then the filter is applied in memory with LINQ to Objects.
Would be interesting to know if the case-sensitivity disappears if you return an Expression.
(Just as a note about your Case-Sensitivity problem, not a solution to your general question about the best way to implement a Search feature.)
I would look at Lucene.Net for a good search provider.
As per your searches using LINQ, you can try something like this and it works just fine:
(x.Title).ToUpper().Contains(query.ToUpper())
Or the similar method of ToLower() should suffice as well.
For databases that truly consider an uppercase 'A' different from a lowercase 'a' as different values, which they are technically are, the above LINQ procedure will get you the results.
Hope this helps.

Accessing foreign keys through LINQ

I have a setup on SQL Server 2008. I've got three tables. One has a string identifier as a primary key. The second table holds indices into an attribute table. The third simply holds foreign keys into both tables- so that the attributes themselves aren't held in the first table but are instead referred to. Apparently this is common in database normalization, although it is still insane because I know that, since the key is a string, it would take a maximum of 1 attribute per 30 first table room entries to yield a space benefit, let alone the time and complexity problems.
How can I write a LINQ to SQL query to only return values from the first table, such that they hold only specific attributes, as defined in the list in the second table? I attempted to use a Join or GroupJoin, but apparently SQL Server 2008 cannot use a Tuple as the return value.
"I attempted to use a Join or
GroupJoin, but apparently SQL Server
2008 cannot use a Tuple as the return
value".
You can use anonymous types instead of Tuples which are supported by Linq2SQL.
IE:
from x in source group x by new {x.Field1, x.Field2}
I'm not quite clear what you're asking for. Some code might help. Are you looking for something like this?
var q = from i in ctx.Items
select new
{
i.ItemId,
i.ItemTitle,
Attributes = from map in i.AttributeMaps
select map.Attribute
};
I use this page all the time for figuring out complex linq queries when I know the sql approach I want to use.
VB http://msdn.microsoft.com/en-us/vbasic/bb688085
C# http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx
If you know how to write the sql query to get the data you want then this will show you how to get the same result translating it into linq syntax.

Categories