Search code examples
c#databasesilverlightvisual-studio-lightswitch

Clear Lightswitch intrinsic database


Lightswitch (Desktop app, out-of-browser) has very limited documentation scattered here and there. I'm looking for a way to clear all data in the intrinsic database in order to add new data after significant changes were made.

Here's the only working solution I have for now:

  1. Write a DeleteAll() method for each and every VisualCollection I have.
  2. Add an event or button to a screen, for example.
  3. Call all the DeleteAll() methods (at event fired or button click).
  4. Save.

This is obviously not efficient at all and very not DRY. What I'd like to have is some kind of ClearDatabase() method that I'd be using only for development and debugging.

So here are the 2 important parts of my question:

  • Can I (and if so, how would I) get all EntitySets in my ApplicationData without hardcoding ?
  • Is it possible to call such a method from the Client side of my app ? I'm thinking maybe in the auto-generated Application.Application_Initialize().

Solution

  • Since at the time of this post there seems to be absolutely no answer to this question on the internet, I came up with new code by digging in Lightswitch's code.

    Here's a working, tested solution I wrote. Just follow those very simple steps.

    1. In the solution explorer, under yourAppName.Server, create a new folder named UserCode, if it doesn't exist already.

    2. In that folder, add a new class named DataUtilities.

    3. Delete all code in that new class, and paste in this code:

      using Microsoft.LightSwitch;
      using Microsoft.LightSwitch.Details;
      using Microsoft.LightSwitch.Framework;
      using Microsoft.LightSwitch.Threading;
      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Diagnostics;
      using System.Linq;
      using System.Reflection;
      
      namespace LightSwitchApplication.UserCode
      {
          public static class DataUtilities
          {
              public static void DeleteAllSets(this DataWorkspace workspace, params Type[] excludedTypes)
              {
                  List<Type> listExcludedTypes = excludedTypes.ToList();
                  ApplicationData appData = workspace.ApplicationData;
                  IEnumerable<IDataServiceProperty> properties = appData.Details.Properties.All();
      
                  foreach (IDataServiceProperty prop in properties)
                  {
                      dynamic entitySet = prop.Value;
                      Type entityType = entitySet.GetType().GetGenericArguments()[0];
      
                      if (!listExcludedTypes.Contains(entityType))
                      {
                          typeof(DataUtilities).GetMethod("DeleteSet", BindingFlags.Static | BindingFlags.Public)
                                              .MakeGenericMethod(entityType)
                                              .Invoke(null, new object[] { entitySet });
                      }
                  }
      
                  appData.SaveChanges();
              }
      
              public static void DeleteSet<T>(this EntitySet<T> entities) where T: 
                  IDispatcherObject, IObjectWithDetails, IStructuralObject, INotifyPropertyChanged, IBusinessObject, IEntityObject
              {
                  List<T> entityList = entities.Select(e => e).Execute().ToList();
                  int entityCount = entityList.Count();
      
                  for (int i = 0; i < entityCount; i++)
                  {
                      T entity = entityList.ElementAt(i);
                      if (entity != null) 
                      { 
                          // Uncomment the line below to see all entities being deleted.
                          // Debug.WriteLine("DELETING " + typeof(T).Name + ": " + entity); 
                          entity.Delete(); 
                      }
                  }
              }
          }
      }
      
    4. Do step 1 again, but this time under yourAppName.DesktopClient. You should now have 2 folders named UserCode, one in both side of the application.

    5. Right-click on that last folder (UserCode in yourAppName.DesktopClient), go to Add and then Existing Element... .

    6. Navigate to ...\yourAppName\yourAppName.Server\UserCode.

    7. Select DataUtilities.cs, and click on the little down arrow besides the Add button. Choose Add as link. Now the class can be used on both Server side AND Client Side.

      Now let's use the new extension methods !

    8. Back in the solution explorer, Right-click on yourAppName.DesktopClient, and select Show Application Code (Should be the first option in the dropdown menu).

    9. Replace the generated code with this (Or, if you had some custom code already in that class, add the single line I show in Application_Initialize()):

      using LightSwitchApplication.UserCode;
      
      namespace LightSwitchApplication
      {
          public partial class Application
          {
              partial void Application_Initialize()
              {
                  Current.CreateDataWorkspace().DeleteAllSets();
              }
      
              //Some other methods here if you already modified this class.
          }
      }
      
    10. Voila ! The next time you start your application, all data stored in the intrinsic database should be gone.


    More info on the code:

    How it works

    I won't explain the whole process here but basically:

    • DeleteAllSets(...) will get all the EntitySets of the data source and call DeleteSet(...) on each one of them.
    • DeleteSet(...) will call the already existing Delete() method on each entity in the EntitySet.

    How to exclude data from deletion

    You can also pass in Type parameters to the DeleteAllSets(...) method to exclude those from the deletion process:

    Lets say I have 2 tables storing employees data and products data respectively. Let those tables be called Employee and Product. If, for example, I had added test data in the Product table, and wanted to get rid of it, without deleting all my employees, I'd use the extension method like this:

    Current.CreateDataWorkspace().DeleteAllSets(typeof(Employee));
    

    This would delete all the entities in the Product table only.


    I hope this helps anyone stuck with Lightswitch's not-so-easy debugging and testing ! The whole process is probably translatable to the Web version, but I'll leave that to someone else.