- Home
- LLBLGen Pro
- Bugs & Issues
LINQ Self Projection
Joined: 04-Jun-2008
Hi,
I realize this isn't supported, but is there any chance you will support "self-projections" in LINQ queries in the future? By that I mean:
from e in metaData.MyEntity
select new {
TheEntity=e,
RelatedEntity=e.SomeOtherEntity
}
It's really a critical feature for us.
Thank you.
It's not that easy to get this working, as it requires a complex projection which is using several query api elements, which is a catch 22: the query api elements themselves are used during their own process.
that said, what you want, is actually doing prefetch paths it seems?
You can work around this by fetching the data using prefetch paths and then calling the Execute method on the ILLBLGenProQuery or ToList() and re-projecting them in-memory.
We do want to add this feature but as said, it's no easy, so we don't know if it will make 3.0.
Joined: 04-Jun-2008
Hi,
Sorry to revive this old thread. Is there any word on this topic?
Basically we've hit a roadblock with this.
Specifically, our problem right now is that we have a rather complex query. This query works fine in C#, but in VB.NET it throws the correlation filter exception. I've looked at the expression tree for VB.NET vs C# for the same query and the difference is that VB.NET always appends .Select(i=>i) to the expression tree at the end, whereas C# no-ops this. I'm guessing the problem is the same as described earlier, given the exact exception, but I can't be sure I guess.
I've attached the complete expression trees.
Our firm is migrating to LINQ across multiple groups and we don't all use LLBLGen. We've been using LLBLGen for 5 years in my specific group since the group's conception. Unfortunately, at this point, this lack of support is the determining factor is a decision to abandon LLBLGen as our data access layer.
Thank you.
Jeff
Joined: 04-Jun-2008
Attachments don't seem to work for me...
VB .NET (doesn't work):
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogEntity]).GroupJoin(value(
SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogEventTypeEntity]), log => log.LogEventTypeId,
lt => Convert(lt.LogEventTypeId), (log, lt1) => new <>f__AnonymousType1d`2(log = log, lt1 = lt1)).SelectMany(
<>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.lt1.DefaultIfEmpty(), (<>h__TransparentIdentifier0, lt)
=> new <>f__AnonymousType1e`2(<>h__TransparentIdentifier0 = <>h__TransparentIdentifier0, lt = lt)).GroupJoin(value(
SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogEventSubTypeEntity]), <>h__TransparentIdentifier1
=> <>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.LogEventSubTypeId, lst => Convert(lst.LogEventSubTypeId),
(<>h__TransparentIdentifier1, lst1) => new <>f__AnonymousType1f`2(<>h__TransparentIdentifier1 = <>h__TransparentIdentifier1,
lst1 = lst1)).SelectMany(<>h__TransparentIdentifier2 => <>h__TransparentIdentifier2.lst1.DefaultIfEmpty(),
(<>h__TransparentIdentifier2, lst) => new <>f__AnonymousType20`2(<>h__TransparentIdentifier2 = <>h__TransparentIdentifier2,
lst = lst)).Join(value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.CategoryLogEntity]),
<>h__TransparentIdentifier3 => <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.
<>h__TransparentIdentifier0.log.LogId, cl => cl.LogId, (<>h__TransparentIdentifier3, cl) => new LogEntry()
{LogId = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.LogId,
Priority = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Priority,
TraceEventType = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Severity,
Title = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Title,
TimeStamp = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Timestamp,
MachineName = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.MachineName,
AppDomainName = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.AppDomainName,
ProcessId = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ProcessId,
ProcessName = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ProcessName,
ManagedThreadName = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ThreadName,
Win32ThreadId = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Win32ThreadId,
Message = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Message,
EventTypeCode = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.lt.LogEventTypeCode,
EventSubTypeCode = <>h__TransparentIdentifier3.lst.LogEventSubTypeCode, Categories = value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[
OurProject.Data.EntityClasses.CategoryEntity]).Where(c => (cl.CategoryId = c.CategoryId)).Select(c => c.CategoryName).ToList(),
LogDetails = value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogDetailEntity]).Where(ld =>
(ld.LogId = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.LogId)).
Select(ld => new Triplet`3(ld.Name, ld.ValueInt, ld.ValueString)).ToList(), ApplicationShortName =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ApplicationShortName}
).Where(i => (i.LogId = 100)).Select(i => i).Take(100)
C# (works):
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogEntity]).GroupJoin(value(
SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogEventTypeEntity]), log => log.LogEventTypeId, lt =>
Convert(lt.LogEventTypeId), (log, lt1) => new <>f__AnonymousType1d`2(log = log, lt1 = lt1)).SelectMany(<>h__TransparentIdentifier0 =>
<>h__TransparentIdentifier0.lt1.DefaultIfEmpty(), (<>h__TransparentIdentifier0, lt) => new <>f__AnonymousType1e`2(<>h__TransparentIdentifier0 =
<>h__TransparentIdentifier0, lt = lt)).GroupJoin(value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogEventSubTypeEntity]),
<>h__TransparentIdentifier1 => <>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.LogEventSubTypeId, lst => Convert(lst.LogEventSubTypeId),
(<>h__TransparentIdentifier1, lst1) => new <>f__AnonymousType1f`2(<>h__TransparentIdentifier1 = <>h__TransparentIdentifier1, lst1 = lst1)).
SelectMany(<>h__TransparentIdentifier2 => <>h__TransparentIdentifier2.lst1.DefaultIfEmpty(), (<>h__TransparentIdentifier2, lst) => new <>f__AnonymousType20`2(
<>h__TransparentIdentifier2 = <>h__TransparentIdentifier2, lst = lst)).Join(value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[
OurProject.Data.EntityClasses.CategoryLogEntity]), <>h__TransparentIdentifier3 => <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.
<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.LogId, cl => cl.LogId, (<>h__TransparentIdentifier3, cl) => new LogEntry()
{LogId = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.LogId,
Priority = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Priority,
TraceEventType = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Severity,
Title = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Title, TimeStamp =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Timestamp, MachineName =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.MachineName, AppDomainName =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.AppDomainName, ProcessId =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ProcessId, ProcessName =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ProcessName, ManagedThreadName =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ThreadName, Win32ThreadId =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Win32ThreadId, Message =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.Message, EventTypeCode =
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.lt.LogEventTypeCode, EventSubTypeCode =
<>h__TransparentIdentifier3.lst.LogEventSubTypeCode, Categories = value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[
OurProject.Data.EntityClasses.CategoryEntity]).Where(c => (cl.CategoryId = c.CategoryId)).Select(c => c.CategoryName).ToList(),
LogDetails = value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[OurProject.Data.EntityClasses.LogDetailEntity]).Where(ld =>
(ld.LogId = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.LogId)).Select(ld =>
new Triplet`3(ld.Name, ld.ValueInt, ld.ValueString)).ToList(), ApplicationShortName = <>h__TransparentIdentifier3.<>h__TransparentIdentifier2.
<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.log.ApplicationShortName}).Where(i => (i.LogId = 100)).Take(100)
I've reformatted the big expression text.
Please try the latest runtime library builds also, as you haven't given any code, it's impossible to debug this. The expression is also too big to debug, as it's impossible to find out what's going on at the level that deep. So try to cut the query into a smaller one which still reproduces the problem. The VB.NET i=>i projection is not a problem, as that's not doing anything. The problem is: .Select(i=>new {I=i}), as that's creating a new type with a projection. Select(i=>i) is a no-op.
IMHO, to reproduce it, it should be a simple (something).Where().take(100) where 'something' is a simple query. Please try to find that query so we can look into this.
The original thread you posted, the projection to anonymous type with entities is something we still want to add to v3's RTL (during beta, but before RTM), however if it's too complex we won't (and it's likely it's too complex as Linq is build on top of our query system). But as said: the new post you made is not related to the original post in this thread (as otherwise C# wouldn't have worked).
Btw, abandoning LLBLGen Pro for this might be understandable (i.e. if you need the projection of the original post in this thread), but other alternatives have different issues with Linq (also l2s and EF), so it's something you might not want to do without proper testing.
Re-examining the expression, I indeed see that the Where().Select(i=>i).Take(100) is inside a projection. I'll see if I can reproduce this in C# (as that should be easy by adding the select())
I can't reproduce it (from what I reverse engineer from the expression)
[Test]
public void GetCustomerIdsWithOrdersInAnonymousType()
{
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
LinqMetaData metaData = new LinqMetaData(adapter);
var q = from c in metaData.Customer
select new {
c.CustomerId,
c.CompanyName,
Orders = metaData.Order.Where(o => o.CustomerId == c.CustomerId).Select(i=>i).Take(5)
};
int count = 0;
foreach(var v in q)
{
count++;
if((v.CompanyName == "FISSA Fabrica Inter. Salchichas S.A.") || (v.CompanyName == "Paris spécialités"))
{
// no orders
continue;
}
Assert.IsTrue(v.Orders.Count() > 0);
Assert.IsTrue(v.Orders.Count()<=5);
}
Assert.AreEqual(91, count);
}
}
works
gives:
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource21[NW26.Adapter.EntityClasses.CustomerEntity]).Select(c => new <>f__AnonymousTypeb0
3(CustomerId = c.CustomerId, CompanyName = c.CompanyName, Orders = value(LinqTester.AdapterTests.DynamicListFetches+<>c__DisplayClass20).metaData.Order.Where(o => (o.CustomerId = c.CustomerId)).Select(i => i).Take(5)))
so the exception must originate from another element in the projection. I'm now porting the test to VB.NET to see if that makes a difference.
Joined: 04-Jun-2008
The VB querying this is in a separate assembly...but all in C#, we have:
var query = from log in metadata.Log
join lt in metadata.LogEventType on log.LogEventTypeId equals lt.LogEventTypeId
into lt1
from lt in lt1.DefaultIfEmpty()
join lst in metadata.LogEventSubType on log.LogEventSubTypeId equals
lst.LogEventSubTypeId into lst1
from lst in lst1.DefaultIfEmpty()
join cl in metadata.CategoryLog on log.LogId equals cl.LogId
select new LogEntry
{
LogId = log.LogId,
Priority = log.Priority,
TraceEventType = log.Severity,
Title = log.Title,
TimeStamp = log.Timestamp,
MachineName = log.MachineName,
AppDomainName = log.AppDomainName,
ProcessId = log.ProcessId,
ProcessName = log.ProcessName,
ManagedThreadName = log.ThreadName,
Win32ThreadId = log.Win32ThreadId,
Message = log.Message,
EventTypeCode = lt.LogEventTypeCode,
EventSubTypeCode = lst.LogEventSubTypeCode,
Categories = (from c in metadata.Category
where
cl.CategoryId == c.CategoryId
select c.CategoryName).ToList(),
//CategoryLookup = log.Severity,
LogDetails = (from ld in metadata.LogDetail
where
ld.LogId == log.LogId
select new Triplet<string, int?, string>(ld.Name, ld.ValueInt, ld.ValueString)).ToList(),
ApplicationShortName = log.ApplicationShortName,
};
.
.
.
return (from i in query select i).Take(100).ToList();
Joined: 04-Jun-2008
Triplet is:
[Serializable]
public class Triplet<TFirst, TSecond, TThird>
{
#region Construcotrs
/// <summary>
/// Initializes a new instance of the <see cref="Triplet<TFirst, TSecond, TThird>"/> class.
/// </summary>
public Triplet()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Triplet<TFirst, TSecond, TThird>"/> class.
/// </summary>
/// <param name="first">The first.</param>
/// <param name="second">The second.</param>
/// <param name="third">The third.</param>
public Triplet(TFirst first, TSecond second, TThird third)
{
First = first;
Second = second;
Third = third;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the first.
/// </summary>
/// <value>The first.</value>
public TFirst First { get; set; }
/// <summary>
/// Gets or sets the second.
/// </summary>
/// <value>The second.</value>
public TSecond Second { get; set; }
/// <summary>
/// Gets or sets the third.
/// </summary>
/// <value>The third.</value>
public TThird Third { get; set; }
#endregion
#region Static methods
/// <summary>
/// Makes the specified first.
/// </summary>
/// <typeparam name="TF">The type of the F.</typeparam>
/// <typeparam name="TS">The type of the S.</typeparam>
/// <typeparam name="TT">The type of the T.</typeparam>
/// <param name="first">The first.</param>
/// <param name="second">The second.</param>
/// <param name="third">The third.</param>
/// <returns></returns>
public static Triplet<TF, TS, TT> Make<TF, TS, TT>(TF first, TS second, TT third)
{
return new Triplet<TF, TS, TT>(first, second, third);
}
#endregion
}
I can reproduce it with this query in VB.NET (same query, ported to VB.NET)
<Test()> _
Public Sub GetCustomerIdsWithOrdersInAnonymousType()
Using adapter As New DataAccessAdapter()
Dim metaData As New LinqMetaData(adapter)
Dim q = From c In metaData.Customer _
Select c.CustomerId, c.CompanyName, Orders = metaData.Order.Where(Function(o) o.CustomerId = c.CustomerId).Take(5)
Dim count As Integer = 0
For Each v In q
count += 1
If (v.CompanyName = "FISSA Fabrica Inter. Salchichas S.A.") OrElse (v.CompanyName = "Paris spécialités") Then
' no orders
Continue For
End If
Assert.IsTrue(v.Orders.Count() > 0)
Assert.IsTrue(v.Orders.Count() <= 5)
Next
Assert.AreEqual(91, count)
End Using
End Sub
gives:
failed: SD.LLBLGen.Pro.ORMSupportClasses.ORMQueryConstructionException : A nested query in the projection has no correlation filter to tie its set to the containing parent row. Please add a correlation filter to the where clause of this query to tie the nested query to the parent. C:\Myprojects\VS.NET Projects\LLBLGen Pro v2.0\LinqSupport\LinqSupportClasses .NET 3.5\ExpressionClasses\QueryExpression.cs(231,0): at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.QueryExpression.FindCorrelationFilterPredicates(IElementCreatorCore generatedCodeElementCreator, MappingTracker trackedMappings) etc.
expression:
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[NW26.Adapter.EntityClasses.CustomerEntity]).Select(c => new VB$AnonymousType_4`3(CustomerId = c.CustomerId, CompanyName = c.CompanyName, Orders = Convert(value(VBTestQueries.DynamicListFetches+_Closure$__1).$VB$Local_metaData.Order).Where(o => (CompareString(o.CustomerId, c.CustomerId, False) = 0)).Take(5)))
(ironically, without the select(i=i) )
So now that we've a repro, we can try to fix it. We'll look into it and get back to you a.s.a.p.
// C#
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[NW26.Adapter.EntityClasses.CustomerEntity])
.Select(c => new <>f__AnonymousTypeb0`3(CustomerId = c.CustomerId, CompanyName = c.CompanyName,
Orders = value(LinqTester.AdapterTests.DynamicListFetches+<>c__DisplayClass20).metaData.Order
.Where(o => (o.CustomerId = c.CustomerId)).Select(i => i).Take(5)))
// VB.NET
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource2`1[NW26.Adapter.EntityClasses.CustomerEntity])
.Select(c => new VB$AnonymousType_4`3(CustomerId = c.CustomerId, CompanyName = c.CompanyName,
Orders = Convert(value(VBTestQueries.DynamicListFetches+_Closure$__1).$VB$Local_metaData.Order)
.Where(o => (CompareString(o.CustomerId, c.CustomerId, False) = 0)).Take(5)))
It's clear why this is: the VB.NET part compares correlated inner query with the outer query using a function call which is executed inside the DB. Normally, this isn't doable, as the database function performs the correlation but it's unclear on what ground (and it can't be executed in-memory to bind outer to inner).
A special case code path could solve this (by hard-coded checks for Compare* methods (vb specific) which then convert these back to a normal binary expression, however, it's also solveable inside the query. I'll look at your C# query and will post the workaround.
(edit) not possible as you fetch a 1:n relationship in the projection of a fetch of the 'n' side (so a m:1 projection. Lots of redundant data!). So there you indeed need the manually specified correlated filter.
Looking into a solution for this. It might be that we need till tomorrow (friday) before a fix is posted.
Ok, the comparestring problem is only happening with string typed pk-fk fields.
However your query doesn't seem to have this, so your query's problem is caused by a different problem (albeit related I think).
Could you comment out as much fields as possible in the projection which still make the query run so the nested query which causes this is identified (and post the vb.net query please)
Joined: 04-Jun-2008
When you say VB .NET query do you mean you want the whole query in VB .NET?
the full query itself is in a C# compiled assembly (so the big part has never been in VB). It's just the caller that uses it in a separate assembly that's VB.
JeffN825 wrote:
Thank you Frans. Your support of the product has never been anything short of outstanding.
JeffN825 wrote:
When you say VB .NET query do you mean you want the whole query in VB .NET?
the full query itself is in a C# compiled assembly (so the big part has never been in VB). It's just the caller that uses it in a separate assembly that's VB.
I found it. I compared the massive expressions with each other and they're completely the same except the Select(i=>i) on the outside as you already suggested.
So doing:
[Test]
public void GetCustomerIdsWithOrdersInAnonymousType()
{
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
LinqMetaData metaData = new LinqMetaData(adapter);
var q = from c in metaData.Customer
select new {
c.CustomerId,
c.CompanyName,
Orders = metaData.Order.Where(o => o.CustomerId == c.CustomerId)
};
q = q.Select(i => i).Take(5);
int count = 0;
foreach(var v in q)
{
count++;
if((v.CompanyName == "FISSA Fabrica Inter. Salchichas S.A.") || (v.CompanyName == "Paris spécialités"))
{
// no orders
continue;
}
Assert.IsTrue(v.Orders.Count() > 0);
Assert.IsTrue(v.Orders.Count()<=5);
}
Assert.AreEqual(91, count);
}
}
indeed gives the same problem in C#, simply because the nested query containing projection isn't the outer projection (so it can't merge the queries).
VB.NET inserts the .Select(i=>i) as there's no Select in the C# expression (as the projection is placed inside the Join's expression), and thus this gives the problem. So all in all a not that common problem but nasty if you run into it.
We'll address these two problems and will release a new build for you a.s.a.p. (but it will be tomorrow (friday) before we'll have it fixed.
I fixed the CompareString() problem, which isn't the one you're facing, and when I strip out the .Select(i=>i) call, some groupby tests fail. It's unclear to me why, so I've to verify why that happens before I can sign off the fix for you.
(edit) fixed it. Wrapping things up, expect a new build in 5 minutes or less attached to a follow up post.
Please see the attached dll for the fixes.
This now also works: var q = metaData.SomeEntity.GroupBy(x=>x.SomeField);
which previously crashed because it didn't have a .Select(x=>x), the one which was added by VB.NET in your query. The provider can now work without the useless select.
JeffN825 wrote:
Thank you! We'll try it out right away.
Your responsiveness fixing these kinds of things speaks worlds.
Thank you Jeff
Just making sure our support quality is above the level of the competition