New Posts New Posts RSS Feed: Save a Query
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Save a Query

 Post Reply Post Reply
Author
ken.nelson View Drop Down
Groupie
Groupie


Joined: 03-Mar-2009
Location: Ann Arbor, MI
Posts: 54
Post Options Post Options   Quote ken.nelson Quote  Post ReplyReply Direct Link To This Post Topic: Save a Query
    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
Back to Top
sbelini View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 13-Aug-2010
Location: Oakland
Posts: 786
Post Options Post Options   Quote sbelini Quote  Post ReplyReply Direct Link To This Post 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.

Back to Top
ken.nelson View Drop Down
Groupie
Groupie


Joined: 03-Mar-2009
Location: Ann Arbor, MI
Posts: 54
Post Options Post Options   Quote ken.nelson Quote  Post ReplyReply Direct Link To This Post 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.

Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post 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
    }



Edited by smi-mark - 11-Aug-2013 at 12:28pm
Back to Top
ken.nelson View Drop Down
Groupie
Groupie


Joined: 03-Mar-2009
Location: Ann Arbor, MI
Posts: 54
Post Options Post Options   Quote ken.nelson Quote  Post ReplyReply Direct Link To This Post 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


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);

Back to Top
ken.nelson View Drop Down
Groupie
Groupie


Joined: 03-Mar-2009
Location: Ann Arbor, MI
Posts: 54
Post Options Post Options   Quote ken.nelson Quote  Post ReplyReply Direct Link To This Post 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!
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down