locked
How to create a Query from a method in a RIA service? RRS feed

  • Question

  • Hello,

    I've created a RIA domain service to query data and build a DTO.  It does not perform any other CRUD operations.  In LightSwitch, I loaded the RIA domain service as a data source, and it works great!  Today, I found that I need to provide another query method that only returns active licenses rather than all licenses.  So, I placed the new query in the data service and updated the Data Source in LightSwitch.  Unfortunately, I cannot seem to create any queries against the GetActiveLicenseDTOs() method.  All queries are going through GetLicensesDTOs().  Is there any way to create a Query in LightSwitch against the other method?  If not, does it mean that I need to create another RIA Domain Service just to get this kind of filtering?

    I'd appreciate your advice,

    Thanks,

    Mike

        public class LicenseDTOsDomainService : LightSwitchDomainServiceBase
        {
            [Query(IsDefault = true)]
            public IQueryable<XXX.RIA.DTO.LicenseDTO> GetLicenseDTOs()
            {
            }

            public IQueryable<XXX.RIA.DTO.LicenseDTO> GetActiveLicenseDTOs()
            {
            }
        }

    Tuesday, July 30, 2013 9:22 PM

Answers

  • You can simply do this "on the LightSwitch side" and you do not need to create an additional query method in the ria service.

    The ria service returns an IQueryable, so if you create a new query in LightSwitch based on the ria data source query (rightclick in the lightswitch data source on your ria query and select add query), the queries will chain perfectly into each other and will perfectly follow the deferred execution pattern.

    The new query will pass indeed through your ria domain service, but it will chain the potential where class you added in the preprocesquery method of your new lightswitch query.


    paul van bladel

    • Marked as answer by A Bit of Help Tuesday, August 6, 2013 9:57 PM
    Tuesday, July 30, 2013 10:02 PM
  • Hmmm... Well, I have VS2013 RC on my system.  I created a new project and tried the code in the preprocessquery and the filter methods.  In both cases, it worked properly.  This was against an instrinsic table, but my real code goes against a RIA (read only) data service.  I will test it next... 
    • Marked as answer by Angie Xu Tuesday, August 6, 2013 11:34 AM
    Wednesday, July 31, 2013 4:25 PM

All replies

  • You can simply do this "on the LightSwitch side" and you do not need to create an additional query method in the ria service.

    The ria service returns an IQueryable, so if you create a new query in LightSwitch based on the ria data source query (rightclick in the lightswitch data source on your ria query and select add query), the queries will chain perfectly into each other and will perfectly follow the deferred execution pattern.

    The new query will pass indeed through your ria domain service, but it will chain the potential where class you added in the preprocesquery method of your new lightswitch query.


    paul van bladel

    • Marked as answer by A Bit of Help Tuesday, August 6, 2013 9:57 PM
    Tuesday, July 30, 2013 10:02 PM
  • Hi Paul,

    Thank you very much for your response!

    So, I've created a query based on the RIA data source, and have attached a screen to it.  When I run the application, I see data on the screen.  Good. :)  Next, I added the preprocessquery method.  I need to filter the data based on settings that the user has configured.  The settings are saved in the Settings table of the database.  So, I retrieve the settings, and see the correct values.  At this point, I'd modify the query to filter based on two settings, but first I want to try to run my application.  Unfortunately, I get an exception (see below): "The underlying provider failed on EnlistTransaction... Connection currently has transaction enlisted.  Finish current transaction and retry.".  BOOM!  I am stuck! :P  All I am doing is querying a table for settings to use for filtering...  I hope that you have some suggestions about how to work around this issue.

    Thank you for your time and help,

    Mike

    ----------------------------------------------

            partial void ActiveLicenseDTOs_PreprocessQuery(ref IQueryable<LicenseDTO> query)
            {
                // Get the settings from the database.
                var settings = (from item in this.DataWorkspace.ApplicationData.Settings
                                      select item).FirstOrDefault();
            }

    -------------------------------------------------------------

    Microsoft.LightSwitch.DataServiceOperationException was unhandled by user code
      HResult=-2146233088
      Message=The underlying provider failed on EnlistTransaction.
      Source=Microsoft.LightSwitch
      StackTrace:
           at Microsoft.LightSwitch.Framework.Base.ExecutableObject.Execute(Boolean allowJoin)
           at Microsoft.LightSwitch.Framework.Base.ExecutableObject`1.Execute()
           at Microsoft.LightSwitch.ServerGenerated.Implementation.QueryImplementation`1.Microsoft.LightSwitch.IDataServiceQueryable<T>.Execute()
           at ExpirationTrax.RIA.Services.LicenseDTOsDomainService.GetLicenseDTOs()
           at GetLicenseDTOs(DomainService , Object[] )
           at System.ServiceModel.DomainServices.Server.ReflectionDomainServiceDescriptionProvider.ReflectionDomainOperationEntry.Invoke(DomainService domainService, Object[] parameters)
           at System.ServiceModel.DomainServices.Server.DomainOperationEntry.Invoke(DomainService domainService, Object[] parameters, Int32& totalCount)
           at System.ServiceModel.DomainServices.Server.DomainService.Query(QueryDescription queryDescription, IEnumerable`1& validationErrors, Int32& totalCount)
      InnerException: System.Data.EntityException
           HResult=-2146233087
           Message=The underlying provider failed on EnlistTransaction.
           Source=System.Data.Entity
           StackTrace:
                at System.Data.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction)
                at System.Data.Objects.ObjectContext.EnsureConnection()
                at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
                at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
                at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
                at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
                at Microsoft.LightSwitch.ServerGenerated.Implementation.QueryImplementation`1.<>c__DisplayClass4.<>c__DisplayClass6.<DoExecution>b__1()
                at Microsoft.LightSwitch.ServerGenerated.Implementation.DataServiceImplementation`1.InvokeOperationCore[T](String operationName, Object[] args, Boolean invokedFromODataClient, Func`1 invokeOperation, Action catchCallback, Action`2 serializeCustomExceptionInfo)
           InnerException: System.InvalidOperationException
                HResult=-2146233079
                Message=Connection currently has transaction enlisted.  Finish current transaction and retry.
                Source=System.Data
                StackTrace:
                     at System.Data.SqlClient.SqlConnection.EnlistTransaction(Transaction transaction)
                     at System.Data.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction)
                InnerException:  
    Tuesday, July 30, 2013 10:38 PM
  • Strange.

    and is it working correctly without the retrieval of the setting data from the other data source?

    Try first with an "hardcoded" setting, just to isolate the problem.


    paul van bladel

    Tuesday, July 30, 2013 10:53 PM
  • Hi Paul,

    I see what you mean, but we are dealing with an even simpler case...  If I don't retrieve the settings record, everything works; Otherwise, I get the exception.  I did a little research, and understand that it is due to trying to have some kind of nested transactions...  I don't know LightSwitch well enough to understand how it does transactions.

    Anyway, I made the following changes and everything works properly...  Now, I just need to figure out why I cannot read my settings in this method. :P

    --------------------------------------

                // Get the settings from the database.
                //var settings = (from item in this.DataWorkspace.ApplicationData.Settings
                //                select item).FirstOrDefault();
                var expirationDays = 10;  // Would come from settings
                var warningDays = 30;     // Would come from settings
                var now = DateTime.UtcNow;
                var expirationLimit = now.AddDays(expirationDays * -1);
                var warningLimit = now.AddDays(warningDays);

                query = query.Where(x => x.Expiration >= expirationLimit && x.Expiration <= warningLimit);

    ----------------------------

    Tuesday, July 30, 2013 11:01 PM
  • It seems there is a problem with the DTC (distributed transaction controller) on your machine.

    Did you install updates on sql server or similar?


    paul van bladel

    Wednesday, July 31, 2013 6:30 AM
  • Hmmm...  I've just rebuilt the development computer and have fully updated it and its software.  Win8 Pro, 64-bit; VS2012 Pro, etc.  I saw that Microsoft has a VS2012 RC4 update available.  I will apply it and see if it corrects the issue.  Are you able to do what I am trying on your computer, Paul?  I'll report back...
    Wednesday, July 31, 2013 3:18 PM
  • Yes, I have done as a test a similar scenario and it just works fine.

    Did you test-deploy already the app. If you do so, you can easily figure out if it has something do do with your dev box.


    paul van bladel

    Wednesday, July 31, 2013 3:20 PM
  • Hmmm...  I am going to create another simple project and try to do this task in it...  I'll report back...  Thanks for your continued interest, Paul! :)
    Wednesday, July 31, 2013 3:53 PM
  • Hmmm... Well, I have VS2013 RC on my system.  I created a new project and tried the code in the preprocessquery and the filter methods.  In both cases, it worked properly.  This was against an instrinsic table, but my real code goes against a RIA (read only) data service.  I will test it next... 
    • Marked as answer by Angie Xu Tuesday, August 6, 2013 11:34 AM
    Wednesday, July 31, 2013 4:25 PM
  • Did you ever get to the bottom of why you are getting the "Connection currently has transaction enlisted. Finish current transaction and retry." error?

    I now have the same issue on a deployed HTML app on a Windows 2012 Server. One entity is inserted/edited via a simple RIA domain service that uses the ServerApplicationContext.Current to load and update and save that entity or insert it as a new entity. The error occurs as soon as the entity is being updated or inserted.

    Everything works fine in debug mode locally from within Visual Studio. DTC seems fine to me, although I tried it with and without DTC started and the result is the same.

    Any thoughts on how to overcome this?

    EDIT: started a new thread as my isssue is with updating/inserting of entities rather than querying entities: LS2013 creating a RIA domain service inside server project does not allow update/insert when using ServerApplicationContext


    Regards, Xander. My Blog


    • Edited by novascape Tuesday, May 6, 2014 1:40 AM
    Monday, May 5, 2014 10:45 PM