I am prototyping a generic data browser over WCF Data Services.
The user can select the entities from a TreeView, thus I cannot hardcode the query result types and have to code the queries (URI or LINQ) dynamically.
To offer joins across different Data Services I am loading the results from each Data Service to the client an try to dynamically join them:
Dim q1 As IQueryable = ctx.Execute(Of Object)(New Uri("Service1.svc/Customers")).ToList.AsQueryable
Dim q2 As IQueryable = ctx.Execute(Of Object)(New Uri("Service2.svc/Orders")).ToList.AsQueryable
Dim j = q1.JoinDynamic("q1", q2, "q2", "q1.CustomerID", "q2.CustomerID", "New (q1.CustomerID as q1id, q1.CompanyName as CompanyName)")
I'm am stuck with a problem using the dynamich Join. See: link text
Is ctx.Execute the right way to query results when the types not known until runtime?
Does someone have a better idea on how to implement dynamic joins over Data Services?
As a workaround I dynamically created the join code via an in-memory assembly. This seems to work fine. I can see the join result in the debugger. I only do not know hot to bind the result to a DataGrid.
Dim codeDomProvider = New VBCodeProvider
Dim cp As New Compiler.CompilerParameters
cp.GenerateExecutable = False
cp.GenerateInMemory = True
cp.CompilerOptions = "/optionexplicit- /optionstrict-"
cp.ReferencedAssemblies.Add(IO.Path.ChangeExtension(My.Application.Info.AssemblyName, "exe"))
cp.ReferencedAssemblies.Add("System.dll")
cp.ReferencedAssemblies.Add("System.Core.dll")
cp.ReferencedAssemblies.Add("System.Data.Services.Client.dll")
Dim sb = New Text.StringBuilder()
sb.Append("Imports System" & vbCrLf)
sb.Append("Imports System.Linq" & vbCrLf)
sb.Append("Imports " & My.Application.Info.AssemblyName & vbCrLf)
sb.Append("Public Class JoinHelper" & vbCrLf)
sb.Append("Public Shared Function GetData() As Object" & vbCrLf)
sb.Append(" Dim ctx1 As New NorthwindDataService.NorthwindEntities(New Uri(""http://localhost:3631/NorthwindDataService.svc/""))" & vbCrLf)
sb.Append(" Dim ctx2 As New SalesDataService.SalesEntities(New Uri(""http://localhost:4354/SalesDataService.svc""))" & vbCrLf)
sb.Append(" Dim q1 as System.Data.Services.Client.QueryOperationResponse (of NorthwindDataService.Customers) = ctx1.Execute(Of NorthwindDataService.Customers)(New Uri(""Customers"", UriKind.Relative))" & vbCrLf)
sb.Append(" Dim q2 as System.Data.Services.Client.QueryOperationResponse (of SalesDataService.CustomerSize) = ctx2.Execute(Of SalesDataService.CustomerSize)(New Uri(""CustomerSize"", UriKind.Relative))" & vbCrLf)
sb.Append(" Dim j = From c In q1 Join s In q2 On c.CustomerID Equals s.CustomerID Select New With {c.CompanyName, s.Size}" & vbCrLf)
'sb.Append(" return j.tostring" & vbCrLf)
sb.Append(" return j" & vbCrLf)
'sb.Append(" r = j.ToList" & vbCrLf)
'sb.Append(" return r" & vbCrLf)
sb.Append("End Function" & vbCrLf)
sb.Append("End Class" & vbCrLf)
sb.Append(vbCrLf)
Dim code = sb.ToString
Dim compilerResults = codeDomProvider.CompileAssemblyFromSource(cp, code)
If compilerResults.Errors.HasErrors Then
Throw New ApplicationException(compilerResults.Errors.Item(0).ToString)
End If
Dim o = compilerResults.CompiledAssembly.CreateInstance("JoinHelper")
Dim t = o.GetType
Dim j = t.InvokeMember("GetData", Reflection.BindingFlags.InvokeMethod, Nothing, o, Nothing)
DataGrid1.ItemsSource = j