none
LocalDomainClient for testing: what is IncludedEntities in QueryCompletedResult good for?

    Question

  • Hello,

    I found the  LocalDomainClient written by Nikhil Kothari (see http://www.nikhilk.net/NET-RIA-Services-ViewModel-Pattern-2.aspx). Because the code was written for some beta version of Slilverlight I updated the code for the relase version of Silverlight. Doing so I came across the class QueryCompleteResult class. I use in my implementation of DomainClient.EndQueryCore. The documentation of this class is very basic. I wonder what the Property IncludedEntities is good for. The property is initialised by the constructor. I feed the constructor with Enumerable.Empty<Entity>(). Is that OK? Are there any circumstances where I have to provide something different?

    Thanks
         Ralf

    P.S.: For your information this is my current implementation of the MockDomainClient:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.ServiceModel.DomainServices.Client;
    using System.Threading;
    
    namespace AdCom.Client.Bl.Mocks
    {
    	/// <summary>
    	/// A base class for a domain client that runs locally.
    	/// </summary>
    	/// <seealso cref="http://www.nikhilk.net/NET-RIA-Services-ViewModel-Pattern-2.aspx"/>
    	public abstract class MockDomainClient : DomainClient
    	{
    		private SynchronizationContext synchronizationContext;
    
    		protected MockDomainClient()
    		{
    			this.synchronizationContext = SynchronizationContext.Current;
    		}
    
    		#region Domain client overrides.
    
    		protected override sealed IAsyncResult BeginInvokeCore( InvokeArgs invokeArgs, AsyncCallback callback, object userState )
    		{
    			object result = Invoke( invokeArgs );
    			InvokeAsyncResult asyncResult = new InvokeAsyncResult( callback, userState, result );
    			this.synchronizationContext.Post( o => ((LocalAsyncResult)o).Complete(), asyncResult );
    			return asyncResult;
    		}
    
    		protected override sealed InvokeCompletedResult EndInvokeCore( IAsyncResult asyncResult )
    		{
    			InvokeAsyncResult localAsyncResult = (InvokeAsyncResult)asyncResult;
    			InvokeCompletedResult result = new InvokeCompletedResult( localAsyncResult.Result );
    			return result;
    		}
    
    		protected override sealed IAsyncResult BeginQueryCore( EntityQuery query, AsyncCallback callback, object userState )
    		{
    			IQueryable<Entity> localQuery = Query( query );
    			LocalAsyncResult asyncResult = new QueryAsyncResult( callback, userState, localQuery );
    			this.synchronizationContext.Post( o => ((LocalAsyncResult)o).Complete(), asyncResult );
    			return asyncResult;
    		}
    
    		protected override sealed QueryCompletedResult EndQueryCore( IAsyncResult asyncResult )
    		{
    			QueryAsyncResult localAsyncResult = (QueryAsyncResult)asyncResult;
    			IEnumerable<ValidationResult> validationErrors = Enumerable.Empty<ValidationResult>();
    			IEnumerable<Entity> entities = localAsyncResult.Entities;
    			IEnumerable<Entity> includedEntities = Enumerable.Empty<Entity>();
    			int entityCount = entities.Count();
    			QueryCompletedResult result = new QueryCompletedResult( entities, includedEntities, entityCount, validationErrors );
    			return result;
    		}
    
    		protected override sealed IAsyncResult BeginSubmitCore( EntityChangeSet changeSet, AsyncCallback callback, object userState )
    		{
    			IEnumerable<ChangeSetEntry> changes = Submit( changeSet );
    			LocalAsyncResult asyncResult = new SubmitAsyncResult( callback, userState, changeSet, changes );
    			synchronizationContext.Post( o => ((LocalAsyncResult)o).Complete(), asyncResult );
    			return asyncResult;
    		}
    
    		protected override sealed SubmitCompletedResult EndSubmitCore( IAsyncResult asyncResult )
    		{
    			SubmitAsyncResult localAsyncResult = (SubmitAsyncResult)asyncResult;
    			EntityChangeSet changeSet = localAsyncResult.ChangeSet;
    			IEnumerable<ChangeSetEntry> operationResults = localAsyncResult.OperationResults;
    			SubmitCompletedResult result = new SubmitCompletedResult( changeSet, operationResults );
    			return result;
    		}
    
    		#endregion
    
    		protected virtual IQueryable<Entity> Query( EntityQuery query )
    		{
    			throw new NotSupportedException( "To be implemented in the derived class" );
    		}
    
    		protected virtual object Invoke( InvokeArgs invokeArgs )
    		{
    			throw new NotSupportedException( "To be implemented in the derived class" );
    		}
    
    		protected virtual IEnumerable<ChangeSetEntry> Submit( EntityChangeSet changeSet )
    		{
    			throw new NotSupportedException( "To be implemented in the derived class" );
    		}
    
    		#region IAsyncResult implementations
    
    		private class LocalAsyncResult : IAsyncResult
    		{
    			private readonly AsyncCallback callback;
    			private readonly object asyncState;
    			private bool completed;
    
    			protected LocalAsyncResult( AsyncCallback callback, object asyncState )
    			{
    				this.callback = callback;
    				this.asyncState = asyncState;
    			}
    
    			#region IAsyncResult Properties
    
    			public object AsyncState
    			{
    				get { return this.asyncState; }
    			}
    
    			public bool IsCompleted
    			{
    				get { return this.completed; }
    			}
    
    			public bool CompletedSynchronously
    			{
    				get { return false; }
    			}
    
    			public WaitHandle AsyncWaitHandle
    			{
    				get { return null; }
    			}
    
    			#endregion
    
    			/// <summary>
    			/// Set the completed flag and call the callback method.
    			/// </summary>
    			public void Complete()
    			{
    				this.completed = true;
    				this.callback( this );
    			}
    		}
    
    		/// <summary>
    		/// Result of an invoke operation.
    		/// </summary>
    		private sealed class InvokeAsyncResult : LocalAsyncResult
    		{
    			private object result;
    
    			public InvokeAsyncResult( AsyncCallback callback, object asyncState, object result )
    				: base( callback, asyncState )
    			{
    				this.result = result;
    			}
    
    			public object Result
    			{
    				get { return this.result; }
    			}
    		}
    
    		/// <summary>
    		/// Result of a query operation.
    		/// </summary>
    		private sealed class QueryAsyncResult : LocalAsyncResult
    		{
    			private readonly IEnumerable<Entity> entities;
    
    			public QueryAsyncResult( AsyncCallback callback, object asyncState, IEnumerable<Entity> entities )
    				: base( callback, asyncState )
    			{
    				this.entities = entities;
    			}
    
    			/// <summary>
    			/// Gets the entities to be returned by a load operation.
    			/// </summary>
    			public IEnumerable<Entity> Entities
    			{
    				get { return entities; }
    			}
    		}
    
    		/// <summary>
    		/// Result of a submit operation.
    		/// </summary>
    		private sealed class SubmitAsyncResult : LocalAsyncResult
    		{
    			private readonly EntityChangeSet changeSet;
    			private readonly IEnumerable<ChangeSetEntry> operationResults;
    
    			public SubmitAsyncResult( AsyncCallback callback, object asyncState, EntityChangeSet changeSet, IEnumerable<ChangeSetEntry> operationResults )
    				: base( callback, asyncState )
    			{
    				this.changeSet = changeSet;
    				this.operationResults = operationResults;
    			}
    
    			/// <summary>
    			/// Gets the change set specified in the submit operation.
    			/// </summary>
    			public EntityChangeSet ChangeSet
    			{
    				get { return changeSet; }
    			}
    
    			/// <summary>
    			/// The System.ServiceModel.DomainServices.Client.ChangeSetEntry results sent
    			/// back from the DomainService for the submit operation.
    			/// </summary>
    			public IEnumerable<ChangeSetEntry> OperationResults
    			{
    				get { return this.operationResults; }
    			}
    		}
    
    		#endregion
    	}
    }
    

     

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.IO;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Runtime.Serialization;
    using System.ServiceModel.DomainServices.Client;
    
    namespace AdCom.Client.Bl.Mocks
    {
    	/// <summary>
    	/// A client only domain client holding entites to be returned by query/load operation.
    	/// </summary>
    	/// <remarks>
    	/// Note that the entites provided by this client are cloned objects of the entities registered
    	/// via the <see cref="M:AddEntity"/> method. Because the cloning uses the <see cref="DataContractSerializer"/>
    	/// to serialize the objects only the properties marked with the <see cref="System.Runtime.Serialization.DataMemberAttribute"/>
    	/// are copied. For any user defined statefull property of the entities the queries will return the 
    	/// default values.
    	/// </remarks>
    	public class MockEntityDomainClient : MockDomainClient
    	{
    		private IDictionary<Type, List<Entity>> entitiesByType = new Dictionary<Type, List<Entity>>();
    
    		/// <summary>
    		/// Default constructor. 
    		/// </summary>
    		public MockEntityDomainClient()
    		{
    		}
    
    		/// <summary>
    		/// Add an entity to this mock container. Any query will act on the entities registered here.
    		/// </summary>
    		/// <remarks>
    		/// If someone is querying the entities in this local domain client
    		/// the caller will get clones of the entity.
    		/// </remarks>
    		public void AddEntity( Entity entity )
    		{
    			Type entityType = entity.GetType();
    
    			List<Entity> entities;
    			if ( !this.entitiesByType.TryGetValue( entityType, out entities ) ) {
    				entities = new List<Entity>();
    				this.entitiesByType.Add( entityType, entities );
    			}
    			entities.Add( entity );
    		}
    
    
    		/// <summary>
    		/// Performs the query on the entities added to this domain client by
    		/// <see cref="M:AddEntity"/>.
    		/// </summary>
    		/// <param name="entityQuery">The entity query.</param>
    		protected override IQueryable<Entity> Query( EntityQuery entityQuery )
    		{
    			Type entityType = entityQuery.EntityType;
    
    			if ( !entitiesByType.ContainsKey( entityType ) )
    				return Enumerable.Empty<Entity>().AsQueryable();
    
    			var queryEntities = entitiesByType[entityType];
    			if ( entityQuery.Query == null ) {
    				var resultClones = CloneEntities( queryEntities );
    				return CloneAsQueryable( queryEntities );
    			}
    
    
    
    			var queryExpression = entityQuery.Query.Expression;
    			var methodExpression = (MethodCallExpression)queryExpression;
    
    			List<Expression> newArguments = new List<Expression>();
    			foreach ( var argumentExpression in methodExpression.Arguments ) {
    				if ( IsInputDataBLOCKED EXPRESSION {
    					var entityArray = ToArray( entityType, queryEntities );
    					var dataExpression = Expression.Constant( entityArray.AsQueryable() );
    					newArguments.Add( dataExpression );
    				}
    				else {
    					newArguments.Add( argumentExpression );
    				}
    			}
    			var updatedExpression = methodExpression.Update( methodExpression.Object, newArguments );
    			var lambdaExpression = Expression.Lambda( updatedExpression );
    			var compiledExpression = lambdaExpression.Compile();
    			var expressionResult = compiledExpression.DynamicInvoke();
    			var enumerableQuery = (EnumerableQuery)expressionResult;
    			var resultEnumerable = (IEnumerable)enumerableQuery;
    			var queryResult = new List<Entity>();
    			foreach ( Entity entity in resultEnumerable ) {
    				queryResult.Add( entity );
    			}
    			return CloneAsQueryable( queryResult );
    		}
    
    		/// <summary>
    		/// Determines whether expression is a placeholder for the entity collection
    		/// the query is acting on.
    		/// </summary>
    		/// <param name="expression">The expression.</param>
    		private bool IsInputDataBLOCKED EXPRESSION
    		{
    			var constantExpression = expression as ConstantExpression;
    			if ( constantExpression == null )
    				return false;
    
    			var expressionValue = constantExpression.Value;
    			var expressionType  = expressionValue.GetType();
    			bool isQuery = expressionType.IsSubclassOf( typeof( EnumerableQuery ) );
    			return isQuery;
    		}
    
    
    		/// <summary>
    		/// Convert the entity list to an array of (derived) objects.
    		/// </summary>
    		private Array ToArray( Type elementType, IList<Entity> elements )
    		{
    			Contract.Assert( elementType.IsSubclassOf( typeof( Entity ) ) );
    
    			int entityCount = elements.Count;
    			var entityArray = Array.CreateInstance( elementType, entityCount );
    			for ( int i = 0; i < entityCount; ++i ) {
    				Entity element = elementsIdea;
    				entityArray.SetValue( element, i );
    			}
    			return entityArray;
    		}
    
    		private IQueryable<Entity> CloneAsQueryable( List<Entity> entites )
    		{
    			var clones = CloneEntities( entites );
    			return clones.AsQueryable();
    		}
    
    		/// <summary>
    		/// Creates clones of the given entities.
    		/// </summary>
    		/// <param name="entities">The entities to clone.</param>
    		/// <returns>A list of cloned objects.</returns>
    		private List<Entity> CloneEntities( List<Entity> entities )
    		{
    			DataContractSerializer serializer = new DataContractSerializer( entities.GetType(), entitiesByType.Keys );
    			using ( var stream = new MemoryStream() ) {
    				serializer.WriteObject( stream, entities );
    				stream.Seek( 0, SeekOrigin.Begin );
    				object clones = serializer.ReadObject( stream );
    				return (List<Entity>)clones;
    			}
    		}
    	}
    }
    


     

    Thursday, August 26, 2010 8:32 AM

Answers

All replies

  • Hi ralias,

    Thanks for posting your LocalDomainClient version it helped me plenty. Did you manage to extend anything on this or given any feedback?

    Thanks

    Wednesday, September 01, 2010 4:15 AM
  • Hi Anton,

    I havn't got any other feedback yet but for now i don't think that I really need the information. I was just curious. The local domain client works pretty well for me and yes, I have extended it a little bit. It is now possible to run real simple queries against the domain client. I will update my orginal posting in a minute.

    BTW: Do you know if there is an easy way to clone entities. I have the problem that whenever I return an entity to the caller it changes its state to "attached". If it is returned again by any query I get an exception because RIA tries to attach the entity angain.

    Sunday, September 05, 2010 11:48 AM
  • Hi ralias,

    Same here after using your code things worked well, very grateful.

    The only thing I can think of is to look at Colin Blair's contrib serializer, but I am not sure if that is exactly what you looking for. Here is the post. http://forums.silverlight.net/forums/t/192094.aspx

    Thanks 

    Sunday, September 05, 2010 12:39 PM
  • Thank you very much for the code ralias!

    I added your domain clients to my library: http://goodiesforria.svn.sourceforge.net/viewvc/goodiesforria/trunk/Casimodo/Casimodo.Lib.Silverlight/Ria/Testing/

    If you want me to change the description or remarks of those classes, then contact me.

    Regards,

    Kasimier Buchcik


    Tuesday, September 07, 2010 12:20 PM
  • Hi Anton,

    thanks, this is exactly what I was looking for.  I will update the source code above. It is now possible to query the same data again and again. I'll update the source code above in a minute.

    Now I only have to implement the submit operation and then the domain client should be sufficient to provide all functionality for mocking and providing design time data.

    Thanks again
        Ralf

    BTW.: Why is the other thread called "Colin Blair's contrib serializer"? Did he write the DataContractSerializer?

    Friday, September 10, 2010 5:34 AM
  • Hi Kasimier,

    tlank you for your feedback. I just added cloning to the mock online domain client (following the hint of Anton). It's now possible to query the same data again. I'm also going to implement the Submit operation. However this will take a while because I'm on holiday for the next two weeks.

    Ralf 

    Friday, September 10, 2010 5:43 AM
  • Ralf, if you need a place for your stuff, then I can give you write access to the library. Would be great to have someone on board who's into testing the RIA Services stuff. The library comes under the MIT licence so everyone can use the code for anything - everywhere.

    Regards,

    Kasimier Buchcik

    Wednesday, September 15, 2010 8:29 PM
  • For a general invitation to the library, see http://forums.silverlight.net/forums/t/201090.aspx

    Regards,

    Kasimier Buchcik

    Wednesday, September 15, 2010 9:13 PM
  • Could someone explain the following 2 items?

    (1) private bool IsInputDataBLOCKED EXPRESSION 
                    

    never used a signature like this. What is the meaning of this? 

     

    (2) when I tried to access the entities directly like

    ViewModel.DomainService.Entity.Count is returning 0 even though I set up entities. What could be the problem?

    Thanks 

    Wednesday, September 29, 2010 4:53 PM
  • (1) is just a problem with this forum. The method is called "IsInputDataExpression"

    (2) Your domain context will contain entities after you executed a query. The domain client just provides the entities the domain context can query.

    Ralf

    Thursday, September 30, 2010 5:50 AM
  • Really appricate your answer. Got the first one resolved. I am still not clear on the second part of the question. Here is my test code

    [TestMethod]
    [Asynchronous]
    [Tag(ASYNC)]
    public void ItCanFindBatchWithoutLoading()
    {
                List<Entity> mockEntities = new List<Entity>()
                {
                    new Person() { ID=1, Name="", Year=1990},
                    new Person() { ID=2, Name="", Year=1990},
                    new Person() { ID=3, Name="", Year=1990}
                };
                DomainService1 service = new DomainService1(new MockDomainClient(mockEntities));
                ViewModel viewModel = new ViewModel(service);
                Assert.AreEqual(3, viewModel.Service.Person.Count);
    }


    I was expecting that, since service here is pointing to the mock domain client, I thought, it would resolve the Person entity with the mock entity.

    Thursday, September 30, 2010 11:41 AM
  • Hi.

    I have a couple of questions:

    1) What about Submit and Invoke mocking?

    2) For Query mocking, is this the way to use your LocalDomain mock?

    [TestClass]
        public class Tests : SilverlightTest
        {
            [TestMethod]
            [Asynchronous]
            [Tag("products")]
            [Tag("async")]
            public void TestMethod1()
            {
                List<Product> mockProducts = new List<Product>()
                {
                    new Product() {Category=new Category() {CategoryName="CategoriaMock"},ProductID=1,ProductName="NomeProdottoMock",UnitPrice=10,UnitsInStock=10,UnitsOnOrder=10,Discontinued=false}
                };
    
                var mockDomainClient = new MockEntityDomainClient();
    
                foreach(Product mockProduct in mockProducts)
                {
                    mockDomainClient.AddEntity(mockProduct);
                }
    
                NWProductsDomainContext ctx = new NWProductsDomainContext(mockDomainClient);
    
                ProductsViewModel vm = new ProductsViewModel(ctx);
    
                EnqueueCallback(() => vm.SearchProducts(""));
                EnqueueConditional(() => !vm.IsBusy);
                EnqueueCallback(() => Assert.AreEqual(new List<Product>(vm.Products).Count, 1));
                EnqueueCallback(() => Assert.AreEqual(new List<Product>(vm.Products)[0].ProductName, "NomeProdottoMock"));
                EnqueueTestComplete();
            }
        }


    Thursday, October 07, 2010 10:54 AM
  • Hi.

    On your CloneEntities() method, I suggest you to use amazing deep cloning solution you can find at:

    http://yinyangme.com/blog/post/Generic-class-for-deep-clone-of-Silverlight-and-C-objects.aspx

    This way, returned collections of entities are fully populated with all related objects.

    CloneEntities
    Thursday, October 07, 2010 12:01 PM
  • Hi Ralias,

    Thanks for the code. I have a similar LocalDomainClient and MockDomainClient based on Nikhil's example and updated to the latest version of Ria.

    In my Silverlight UI, when using my normal DomainContext with the WebDomainClient,  I have busy indicators that get displayed when an async query takes a long time to complete.

    I'm trying to have these busy indicators displayed when using the MockDomainClient, but not sure where to put the Thread.Sleep to simulate a long-running server task. I tried putting it in the MockDomainClient.Query() but instead of indicators display my UI freezes for the duration of the Sleep() call.

    How would you simulate a long-running async call with the Mock ?

    Friday, November 05, 2010 2:13 PM
  • Hi innovactive,

    the query example is implemented in the same way i do. Mocking invoke operations in a generic way is a bit complicated. If I need to mock invoke operation I usually write a specialized domain client. However the submit for insert, update and delete can be implemented in a geric way:

    		/// <summary>
    		/// Performs the submit operation.
    		/// </summary>
    		/// <remarks>
    		/// The implementation adds the entities in the change set <c>AddedEntities</c>,
    		/// removes the existing entities submitted in the change set <c>RemovedEntities</c> and
    		/// replaces the entities provided int the changeset <c>ModifiedEntities</c>.
    		/// </remarks>
    		/// <param name="changeSet">The changes of the submit operation.</param>
    		protected override IEnumerable<ChangeSetEntry> Submit( EntityChangeSet changeSet )
    		{
    			var changes = changeSet.GetChangeSetEntries();
    
    			foreach ( var insertedEntity in changeSet.AddedEntities ) {
    				var entitySet = GetEntityListByType( insertedEntity.GetType() );
    				entitySet.Add( insertedEntity );
    			}
    			foreach ( var updatedEntity in changeSet.ModifiedEntities ) {
    				var entitySet = GetEntityListByType( updatedEntity.GetType() );
    				var existingEntity = entitySet.First( e => e.GetIdentity().Equals( updatedEntity.GetIdentity() ) );
    				entitySet.Remove( existingEntity );
    				entitySet.Add( updatedEntity );
    			}
    
    			foreach ( var removedEntity in changeSet.RemovedEntities ) {
    				var entitySet = GetEntityListByType( removedEntity.GetType() );
    				var existingEntity = entitySet.First( e => e.GetIdentity().Equals( removedEntity.GetIdentity() ) );
    				entitySet.Remove( existingEntity );
    			}
    			return changes;
    		}
    
    


    Ralf

     

     

    Friday, March 11, 2011 3:54 AM
  • Hello everyone,

    I'm using the MockDomainClient described above for view model testing purpose and I have an issue while trying to perform a LoadOperation with an enity query with a where and orderby clauses.

    EntityQuery<TransitOperation> query =
                    from c in this._context.GetTransitOperationsQuery()
                    where c.TransitDraftDate == DateTime.Today
                    orderby c.PK
                    select c;

    LoadOperation lo = this._context.Load(query);

    The problem comes from the Query method, especially the part :

    var methodExpression = (MethodCallExpression)queryExpression;

    It returns a methodExpression with 2 arguments while there should be three :

    1) TransitOperation[].Where.....
    2) OrderBy...

    instead of

    1) TransitOperation[]
    2) Where....
    3) OrderBy...

    The following code works fine but no entities are retrieved from the queryResult.

    Has any of you guys ever noticed this? Do you know a way to fix this?


    Thanks!

    tlbarker

    Thursday, March 31, 2011 9:33 AM
  • Thanks for sharing this code and please allow me to add a modest contribuition. In the Query method I added a loop to walk the tree and find the constant expression in case there are methods like skip and take in it:


            /// <summary>
            /// Performs the query on the entities added to this domain client by
            /// <see cref="M:AddEntity"/>.
            /// </summary>
            /// <param name="entityQuery">The entity query.</param>
            protected override IQueryable<Entity> Query(EntityQuery entityQuery)
            {
                Type entityType = entityQuery.EntityType;
    
                if (!entitiesByType.ContainsKey(entityType))
                    return Enumerable.Empty<Entity>().AsQueryable();
    
                var queryEntities = entitiesByType[entityType];
                if (entityQuery.Query == null)
                {
                    var resultClones = CloneEntities(queryEntities);
                    return CloneAsQueryable(queryEntities);
                }
    
                var queryExpression = entityQuery.Query.Expression;
                var methodExpression = (MethodCallExpression)queryExpression;
    
                var currentMethodExpression = methodExpression;
                var exit = false;
    
                // if we have skip and takes the constant will be at the end of the tree...
    
                while (!(currentMethodExpression == null || exit))
                {
                    var nestedMethodExpression = currentMethodExpression.Arguments.OfType<MethodCallExpression>().FirstOrDefault();
                    if (nestedMethodExpression != null)
                    {
                        foreach (var innerArgumentExpression in nestedMethodExpression.Arguments)
                        {
                            if (IsInputData(innerArgumentExpression))
                            {
                                methodExpression = nestedMethodExpression;
                                exit = true;
                                break;
                            }
                        }
                    }
    
                    currentMethodExpression = nestedMethodExpression;
                }
    
                List<Expression> newArguments = new List<Expression>();
                foreach (var argumentExpression in methodExpression.Arguments)
                {
                    if (IsInputData(argumentExpression))
                    {
                        var entityArray = ToArray(entityType, queryEntities);
                        var dataExpression = Expression.Constant(entityArray.AsQueryable());
                        newArguments.Add(dataExpression);
                    }
                    else
                    {
                        newArguments.Add(argumentExpression);
                    }
                }
    
                var updatedExpression = methodExpression.Update(methodExpression.Object, newArguments);
                var lambdaExpression = Expression.Lambda(updatedExpression);
                var compiledExpression = lambdaExpression.Compile();
                var expressionResult = compiledExpression.DynamicInvoke();
                var enumerableQuery = (EnumerableQuery)expressionResult;
                var resultEnumerable = (IEnumerable)enumerableQuery;
                var queryResult = new List<Entity>();
    
                foreach (Entity entity in resultEnumerable)
                {
                    queryResult.Add(entity);
                }
                return CloneAsQueryable(queryResult);
            }


    Friday, June 17, 2011 5:50 AM