Print Page | Close Window

Save a Query

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2012
Forum Discription: For .NET 4.5
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=4265
Printed Date: 24-Oct-2025 at 2:39pm


Topic: Save a Query
Posted By: ken.nelson
Subject: Save a Query
Date Posted: 08-Aug-2013 at 7:19am
Is there any way to save an EntityQuery? Not the results of a query, but the query itself or even a representation of the query (PredicateDescription, SQL), such that an EntityQuery could be constructed at a later time? We're using Silverlight.

Our users have requested an ability to define filters (build a dynamic query), save those filters, and have those filters be loaded back into the application. The user can then select a previously defined filter and have it execute to get the current results. We can't simply save the results of the query because the results of these queries may change over time.

Things I've tried:
  • My first thought was to convert the LINQ-based EntityQuery to SQL, store the SQL string, and later create a PassthruEsqlQuery from the stored SQL, but I can't seem to find a way to convert the EntityQuery to SQL on the Silverlight client.
  • I considered just serializing the EntityQuery or a PredicateDescription as XML using a DataContractSerializer but neither are marked with [DataContract].
  • I noticed that EntityQuery has an Expression property, and I tried converting it to the "for internal use" SerializedExpression which is marked with a [DataContract] but I'm obviously doing something wrong there because I keep getting exceptions while attempting to serialize.
  • My latest attempt was to try serializing as binary using a memory stream, but the BinaryFormatter doesn't seem to exist in the Silverlight libraries.
I feel like there has to be an easy way to accomplish this but I'm running out of ideas.

Thanks,
Ken



Replies:
Posted By: sbelini
Date Posted: 08-Aug-2013 at 3:31pm
Hi Ken,

It won't be a simple task.

As far as sending the query to the server, you could do it by following the steps at http://www.ideablade.com/forum/forum_posts.asp?TID=3187&PID=12343#12343.

Once in the server, you could handle the SerializableExpression as you see fit.



Posted By: ken.nelson
Date Posted: 09-Aug-2013 at 7:55am
That's basically what I was attempting in my 3rd option, but I can't seem to get it to work. I'm getting an exception when I try to send the SerializedExpression to our server.

var p1 = PredicateBuilder.Make<Requirement>(i => i.FTN.Contains("345"));
var q = ASTEM.Requirements.Where(p1);
var expr = SerializedExpression.ToSerializedExpression(q.Expression);

// At this point we send expr to our web service method.

'Type 'IdeaBlade.Core.TypeWrapper' with data contract name 'TypeWrapper:http://ideablade.com/Core' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

So to eliminate our call to our web service method being the issue, I tried:

var p1 = PredicateBuilder.Make<Requirement>(i => i.FTN.Contains("345"));
var q = ASTEM.Requirements.Where(p1);
var expr = SerializedExpression.ToSerializedExpression(q.Expression);

var serializer = new DataContractSerializer(expr.GetType());

byte[] data = null;
using (var stream = new MemoryStream())
{
        serializer.WriteObject(stream, expr);
        stream.Seek(0, SeekOrigin.Begin);
        data = stream.GetBuffer();
}

Which results in the same exception when calling serializer.WriteObject().

If I add TypeWrapper as a known type by doing the following, I receive the same exception for a different type:

var knownTypes = new List<Type>()
{
        typeof(IdeaBlade.Core.TypeWrapper)
}:

var serializer = new DataContractSerializer(expr.GetType(), knownTypes);

Type 'IdeaBlade.EntityModel.EntityQueryProxy`1[[AST.ObjectModel.Requirement, AST.ObjectModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=dba36b71950587e5]]' with data contract name 'EntityQueryProxyOfRequirement_PBxM0UCr:http://ideablade.com/EntityModel' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

And if I add expr.GetType() to the known types list, it doesn't appear to help at all. I continue to get that same exception.

var knownTypes = new List<Type>()
{
        typeof(IdeaBlade.Core.TypeWrapper),
        expr.GetType()
}:

var serializer = new DataContractSerializer(expr.GetType(), knownTypes);

Type 'IdeaBlade.EntityModel.EntityQueryProxy`1[[AST.ObjectModel.Requirement, AST.ObjectModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=dba36b71950587e5]]' with data contract name 'EntityQueryProxyOfRequirement_PBxM0UCr:http://ideablade.com/EntityModel' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.



Posted By: smi-mark
Date Posted: 11-Aug-2013 at 12:26pm
We don't save queries but we do pass expressions to the server.

An example would be something like:


Expression<Func<Customer, bool>> filter = c => c.Name == "bob";
var expr = SerializedExpression.ToSerializedExpression(filter);


We can then pass expr to our remote server method, and I assume you can simply save it on your end.

Hope that helps.

One last piece that I should mention. We had to add SerializedExpression to the list of known types. We do it like this:


    public class KnownTypeProvider : IKnownTypeProvider
    {
        #region Implementation of IKnownTypeProvider

        public IEnumerable<Type> AddKnownTypes()
        {
            return new[]
                       {
                           typeof(SerializedExpression),
                           typeof(List<SerializedExpression>),
                       };
        }

        #endregion
    }



Posted By: ken.nelson
Date Posted: 12-Aug-2013 at 8:37am
Ah okay, I'll give that a shot. The post that was linked seems to indicate that converting the query's Expression to a SerializedExpression should work.

From http://www.ideablade.com/forum/forum_posts.asp?TID=3187&PID=12343#12343 - http://www.ideablade.com/forum/forum_posts.asp?TID=3187&PID=12343#12343


You could instead build up the dynamic query on your client and pass the query expression to your server method. It would look something like this:

var p1 = PredicateBuilder.Make<Product>(p => p.Discontinued == false);
var ss = new SortSelector(typeof(Product), "ProductName");
var query = em.Products.Where(p1).OrderBySelector(ss);

var exp = SerializedExpression.ToSerializedExpression(query.Expression);



Posted By: ken.nelson
Date Posted: 12-Aug-2013 at 11:28am
Thanks smi-mark, your suggestion worked, although I still had to add TypeWrapper as a known type for whatever reason.

Thanks!



Print Page | Close Window