Print Page | Close Window

Using Max and Min

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=2339
Printed Date: 29-Jul-2026 at 3:08pm


Topic: Using Max and Min
Posted By: tj62
Subject: Using Max and Min
Date Posted: 26-Nov-2010 at 7:21am
Hi,
I'm not very good at LINQ but am very good on old fashioned SQL. I'm using DevForce with Silverlight.
 
I have to implement the follwing SQL query in LINQ to Entities:
select max(geo_x), max(geo_y), min(geo_x), min(geo_y) from em_point where customer_id=39 and p_gr_id=1;

The Entity for the table em_point is EntPoint and the variablse are p_geoX, p_geoY, p_customerID, p_groupID;

So I try something like:
 
                var query = p_manager.EntPointSet
                    .Where(p => p.p_customerID == pg.p_customerID && p.p_pointGrID == pg.p_pointGrID)
                    .Where(p => !(p.p_geoX == 0 && p.p_geoY == 0))
                    .Max(p => p.p_geoX);
                Query(query, callback);

Unfortunately this is not possible as query is of type double but not IEntityQuery as expected.

Even if this worked I would have to do 4 such queries for Min and Max to get the same result as in the single line SQL statement.
Is there any way to do the simple SQL statement in a single LINQ to Entities statement?

Retrieving all EntPoint first and then calculating the maxes and mins at the client side is not an option as the number of records from EntPoint is huge.

 





Replies:
Posted By: kimj
Date Posted: 26-Nov-2010 at 1:21pm
In LINQ, and DevForce, Max and Min result in "immediate execution" queries, that is, a query object is not actually constructed but instead the expression is executed right away.   This is why you see a double returned from the expression and not an EntityQuery. 
 
In Silverlight, where queries must be submitted asynchronously, you can use the AsScalarAsync() extension method to turn an immediate execution query into an asynchronously executed one.  So if you wanted to issue separate min and max queries you could do something like this:
 
  var op = p_manager.EntPointSet.Where(...).Select(p => p.p_geoX).AsScalarAsync().Max();
It's probably much easier to instead take advantage of grouping and anonymous projections, and do something like this instead:
 
      var query = p_manager.EntPointSet
                .Where(p => p.p_customerId = ...)
                .GroupBy(p => new { p.p_customerId, p.p_pointGrId })
                .Select(g => new {
                  Id = g.Key,
                  MaxGeoX = g.Max(p => p.p_geoX),
                  MinGeoX = g.Min(p => p.p_geoX),
                  .....
                });
This returns a query, which can  be executed synchronously or asynchronously.


Posted By: tj62
Date Posted: 27-Nov-2010 at 1:05am
Thank you kimj. Actualy where I was failing was formulateing the GroupBy cluse. This all compiles now, but when I run it I get an exceptoin with this error message from the Informix 11.5 Cheeta database:
  ERROR [42000] [IBM][IDS/NT32] A syntax error has occurred.
Can I somewhere se the SQL-query that is generated and run against the database?
Can I somehow influence the SQL-generation to avoid this syntax error?

Here is the LINQ query I'm running:
 var query = p_manager.EntPointSet
                    .Where(p => p.p_customerID == pg.p_customerID && p.p_pointGrID == pg.p_pointGrID)
                    .Where(p => !(p.p_geoX == 0 && p.p_geoY == 0))
                    .GroupBy(p => new { p.p_customerID, p.p_pointGrID })
                    .Select(g => new {
                                        m_id = g.Key,
                                        m_maxGeoX = g.Max(p => p.p_geoX),
                                        m_minGeoX = g.Min(p => p.p_geoX),
                                        m_maxGeoY = g.Max(p => p.p_geoY),
                                        m_minGeoY = g.Min(p => p.p_geoY)
                                    }
                        );
                Query(query, g =>
                {
                    var mapBoundaries = new MapBoundaries();
                    if(g != null)
                    {
                        var enumerator = g.GetEnumerator();
                        enumerator.MoveNext();
                        var p = enumerator.Current;
                        if (p != null)
                        {
                            mapBoundaries.p_leftTop = new Point(p.m_minGeoX, p.m_maxGeoY);
                            mapBoundaries.p_rightBottom = new Point(p.m_maxGeoX, p.m_minGeoY);
                        }
                    }
                    callback(mapBoundaries);
                });


Posted By: kimj
Date Posted: 27-Nov-2010 at 2:09pm
You can see the SQL query by adding the logTraceString attribute to the EdmKey.  You might be using a connectionString element rather than an EdmKey, but in releases prior to 6.0.7 the only way of logging the generated SQL is through this flag on the EdmKey; fortunately it's easy enough to add to your .config file.  Here's more info: http://drc.ideablade.com/xwiki/bin/view/Documentation/Configuration - http://drc.ideablade.com/xwiki/bin/view/Documentation/Configuration


Posted By: tj62
Date Posted: 13-Dec-2010 at 6:55am
When you say "prior to 6.0.7" is there an more easy to use or powerfull alternative in version 6.0.7?


Posted By: kimj
Date Posted: 13-Dec-2010 at 8:53am
Version 6.0.7 added an attribute called shouldLogSqlQueries to the <logging> element.  It does exactly the same thing as the logTraceString attribute on the EdmKey; it's easier to apply since it doesn't require the EdmKey definition, and it will apply to all EF data sources.


Posted By: tj62
Date Posted: 13-Dec-2010 at 9:29am

The previous apporach seemed only show select statements, but not update, insert and delete. Is it possible somehow to se those generated SQL  commands?

Is that maybe supported in this new version 6.0.7?


Posted By: kimj
Date Posted: 13-Dec-2010 at 9:58am

Both the EdmKey.LogTraceString and Logging.ShouldLogSqlQueries only show queries.  There's currently no way within DevForce to see insert/update/delete statements.   The reason for this is that DevForce just uses the EF ToTraceString() method to grab the SQL query, and there's no corresponding method to easily grab the SQL generated for the insert/update/delete commands created during SaveChanges processing.

If using SQL Server there's always SQL Profiler.   There are also 3rd party tools, such as EF Profiler. 


Posted By: chuckc
Date Posted: 19-Jan-2011 at 11:43am
How do you use ToTraceString with a DevForce IEntityQuery query?  The examples I find for ToTraceString all refer to ObjectQuery.  Is there some way to convert an IEntityQuery to an ObjectQuery?

I'd prefer not to use the full DevForce trace logging - I'd just like to inspect an ocaissional query in the debugger.

Thanks.


Posted By: kimj
Date Posted: 19-Jan-2011 at 9:49pm
Tracing of queries within DevForce can only be done for all queries or limited to those for a specific EdmKey.  Afraid there's no way to convert a DevForce EntityQuery into an EF ObjectQuery, and the ToTraceString method is not supported on EntityQuery.



Print Page | Close Window