Showing posts with label Data. Show all posts
Showing posts with label Data. Show all posts

Tuesday, February 5, 2013

Can I delete this?

In a previous post I suggested a way to override default LightSwitch add/edit behavior. In this post I will suggest an override to default delete behavior.
It has happened many times to delete entries, only to get an error message, when trying to save, informing me about reference constraints being violated and the action cannot be completed. This is not much of problem when you try to delete one record (apart from the fact this message is ugly and not one that I would allow my end users to deal with, for that matter). But when trying to delete many records you have no clue which was the one (or more) record(s) that cannot be deleted. In this case all you can do is delete-save until you find the record that cannot be deleted. And when you find it, you have to refresh your screen or undo the changes of the current record (a future article will suggest a way to do this).
What I needed was a good generic way to be able to set Delete_CanExecute result. This is my suggestion using (what else) extension methods, interfaces (Yann will love me for this Smile) and an attribute.
First the interface to help decide if an instance can be deleted or not:
public interface IDependencyCheck : IEntityObject
{
  bool CanDelete { get; }
}



Quite simple you must admit. Keep in mind interfaces you want to use in your common project have to be accessible both by Server and Client project also. If someone here thinks of EntityName_CanDelete, someone forgets that it is a server side hook.

Now an attribute to help us decide which of the dependencies an entity might have are strong ones, meaning that the referential integrity of the database or your business logic if you don’t use database constraints, would not allow an instance to be deleted.
[AttributeUsage(AttributeTargets.Class)]
public class StrongDependencyAttribute : Attribute
{
  public StrongDependencyAttribute(string dependencies) {
    this.dependencies = dependencies.ToStringArray();
  }

  public string[] Dependencies {
    get { return dependencies; }
  }

  private readonly string[] dependencies;
}

This attribute takes a list of strong reference property names as comma delimited string (or whatever delimiter you like for that matter) using these simple extensions:
public static string[] ToStringArray(this string strings) {
   return strings.ToStringArray(',');
}

public static string[] ToStringArray(this string strings, char delimiter) {
   return (from string item in strings.Split(new char[] { delimiter }, StringSplitOptions.RemoveEmptyEntries)
               select item.Trim()).ToArray();
}



If you want to use another delimiter just replace
this.dependencies = dependencies.ToStringArray();



in the constructor with (for example):
this.dependencies = dependencies.ToStringArray(';');

Or if you want, you can have one instance of the attribute for each property you want to check and avoid delimited strings altogether. Plenty of choices…Smile.

Keep in mind that if you declare no instance of this attribute but you implement IDependencyCheck then ALL dependencies will be considered as strong ones and checked for integrity.

This attribute needs to be accessible by the Common project only.

Now, all that said, there are two extension methods that will help us do the job.

The first one needs to be accessible by the Client project only:
public static bool CanDeleteSelection(this IScreenObject screen, string collectionName) {
   if (!screen.HasSelection(collectionName))
     return false;
   IVisualCollection collection = screen.Details.Properties[collectionName].Value as IVisualCollection;
   if (collection.SelectedItem is IDependencyCheck)
     return (collection.SelectedItem as IDependencyCheck).CanDelete;
   return true;
}



Please note I am using IScreenObject.HasSelection extension that has already been introduced in a previous post. That’s why I am not checking if the cast to IVisualCollection is successful (not null).

The second one has to be accessible by the Common project only:
    public static bool CanDelete(this IEntityObject entity) {
      IEnumerable<IEntityCollectionProperty> collectionProperties = 
        entity.Details.Properties.All()
        .Where(p => p.GetType().GetInterfaces()
          .Where(t => t.Name.Equals("IEntityCollectionProperty"))
          .FirstOrDefault() != null)
        .Cast<IEntityCollectionProperty>();
      if (collectionProperties == null)
        return true;
      List<string> strongDependencies = new List<string>();
      IEnumerable<StrongDependencyAttribute> dependencies = 
        entity.GetType()
        .GetCustomAttributes(typeof(StrongDependencyAttribute), false)
        .Cast<StrongDependencyAttribute>();
      foreach (StrongDependencyAttribute dependency in dependencies)
        strongDependencies.AddRange(dependency.Dependencies);
      bool hasDependencies = strongDependencies.FirstOrDefault() != null;
      bool canDelete = true;
      foreach (IEntityCollectionProperty property in collectionProperties) {
        if (hasDependencies &&strongDependencies.FirstOrDefault(d => d.Equals(property.Name)) == null)
          continue;
        IEnumerable value = entity.GetType()
          .GetProperty(string.Format("{0}Query", property.Name))
          .GetValue(entity, null) as IEnumerable;
        try {
          if (value != null && value.GetEnumerator().MoveNext()) {
            canDelete = false;
            break;
          }
        }
        catch {
          continue;
        }
      }
      return canDelete;
    }



Although it’s obvious at first glance what the code does Hot smile, I will give brief explanation:

If there is not a StrongDependencyAtttibute defined for the entity then all reference properties are checked and if at least one has members then the entity cannot be deleted. If a StrongDependencyAtttibute is defined for the entity then only reference properties included in the attribute are checked. That’s all…

If you manage to read the code (I am not very proud about the absence of comments) you will notice that only one-to-many and many-to-many references are handled. In my world one-to-one references mean inheritance and in this case both objects should be deleted. But what if the base object can be deleted (has no direct references) and the derived object has? Again in my world, if you are trying to delete the base object you are already doing it wrong! Anyway if someone lives in a world other than mine (I am very democratic guy Be right back) and wants to support one-to-one relations all he/she has to do is find where IEntityCollectionProperty definition is and look for the respective property type (I believe it is IEntityReferenceProperty but I am not quite sure).

And for the end an example so that anyone can see what all of the above end up to:

Suppose you have a Customer entity. And this Customer entity has a collection of Orders. The property of the Customer entity that holds these orders is called CustomerOrders. In your Datasource you right-click Customer entity and select View Table Code. A partial class implementation file is created (if it does not already exist). Modify the definition of you class as follows:
[StrongDependency("CustomerOrders")]
public partial class Customer : IDependencyCheck {
...

  #region IDependencyCheck members 
  public bool CanDelete {
    get { return this.CanDelete(); }
  }
  #endregion IDependencyCheck members
}



Remember to reference (using) the namespace where your extension method (CanDelete) is declared.

Please note that IDependencyCheck gives you the potential to write whatever else hardcoded (or not) check you want in your CanDelete property implementation. In the code above I just call the extension method I introduced earlier. But you can do whatever you want. You can even skip the dependencies mechanism suggested altogether. The client side extension will still work.

So in the screen that you have your list of Customers right click the Delete command of the list or grid and in the CustomersDelete_CanExecute just write:
partial void CustomersDelete_CanExecute(ref bool result){
  result = this.CanDeleteSelection("Customers");
}



As partial implementation of Execute write:
partial void CustomersDelete_Execute(){
  this.Customers.DeleteSelected();
}



I know some of you have already noticed the overhead of potentially loading the dependent objects the first time you select an item of your list or grid. I cannot argue with that, except for the fact that my approach is suggested for intranet implementations (I am not sure I would do something like that over the web) and the fact that the time under these circumstances is an acceptable price to pay in order to avoid the annoying referential integrity message. At least in my world Smile

Friday, June 22, 2012

RIAlity Issues

Recently I had to face a very frustrating issue regarding the integration of a RIA Service as a LightSwitch Datasource. I tried to find references for it in the web. I did. But none of them (at least the ones I managed to find) didn’t seem to match my case. So after solving my issue I thought sharing was a good idea…
After having implemented and tested my RIA service using a small Silverlight application I decided to add a datasource and use it. Which I did. Focusing at the part of the RIA service that caused the problem, I had a class called ImageAttachment and 2 queries exposing it. Below you can see the initial code:
   1:      [Query(IsDefault = true)]
   2:      public IQueryable<ImageAttachment> GetImageAttachments() {
   3:        return new List<ImageAttachment>().AsQueryable();
   4:      }
   5:   
   6:      public IQueryable<ImageAttachment> GetFolderItemImageAttachments(Guid? providerId, string folderId, string mailItemId) {
   7:        if (!providerId.HasValue || folderId == null || mailItemId == null)
   8:          return GetImageAttachments();
   9:        return GetAttachments(providerId.Value, folderId, mailItemId);
  10:      }



Importing the RIA Service GetFolderItemImageAttachments was properly imported as an optional query for ImageAttachment.

image

I added an ImageAttachment visual collection in a screen fetching results from GetFolderItemImageAttachments query. Everything worked smoothly. But when the time came to load the visual collection (i.e. run the query) I got an exception I hadn’t come across before neither as a LS developer nor as a Silverlight one:

Load operation failed for query ‘GetFolderItemImageAttachments’.  The remote server returned an error: NotFound.

The behavior was very strange. Although the query was recognized and imported from LS for some reason at runtime it looked like the method was not found. I placed a breakpoint at the method and it didn’t hit. The method was never called. Before doing this I was sure it was some bug of mine in the implementation that caused the RIA service to throw this generic exception. But no! The execution never reached the web method. It was then that I decided to “google” it. Looked like it was a RIA Services+LightSwitch(?) issue. All references where either not appropriate in my case or had no effect. Then I did what I usually do when I have problem I cannot solve: I scrolled to the part of code listed above and started to just stare at the code waiting for an answer. And I came to me! Why not make sure the query method IS a query? So what I did was just add the QueryAttribute to my method with no parameters:

   1:      [Query(IsDefault = true)]
   2:      public IQueryable<ImageAttachment> GetImageAttachments() {
   3:        return new List<ImageAttachment>().AsQueryable();
   4:      }
   5:   
   6:      [Query]
   7:      public IQueryable<ImageAttachment> GetFolderItemImageAttachments(Guid? providerId, string folderId, string mailItemId) {
   8:        if (!providerId.HasValue || folderId == null || mailItemId == null)
   9:          return GetImageAttachments();
  10:        return GetAttachments(providerId.Value, folderId, mailItemId);
  11:      }




I thought that if it didn’t solve the problem I surely would not cause a new one. It IS a query method after all. Why let LS infer it? And it worked.

I am quite sure I was lucky. I mean, the query was recognized either way. I cannot explain what exactly was the bug the QueryAttribute fixed. To stress my point more, I have to admit that went back to the RIA Service and I removed the attribute. Still worked! Like a deadlock resolved. Maybe only LightSwitch Team can explain. Anyhow I thought of sharing in case anyone else runs into something like this.Smile

Tuesday, February 7, 2012

Re-Views

In previous posts I made reference to views (DB or RIA) as an alternative (amongst other well-known potentials of views) to search and sort against fields that would normally be relations (lookups or however you want to call them).
From the very beginning I had an issue with SQL Server views imported to LS. LightSwitch had a very strange way to define the primary keys of the views. These “inferred” primary keys are most of the time very complex combined keys. And this is not an issue actually until you decide to add a relationship between this view (which 99% of the times has only one field as actual primary key) and another table. Then you realize this, otherwise benign, complex primary key is an issue (to say the least).
It was only recently, in this thread, after Yann Duran’s suggested reading (always to the rescue and always having something useful to contribute), that I managed to both understand how LS “infers” the Primary Key for a View and realize how one can “force” a primary key.
The bottom line is that LS decides that all not-nullable fields will be part of the inferred primary key. Not very inspired but I must admit I cannot think of anything better. So, how one can force the primary key one wants? The way is re-introducing all you not-nullable, non-key fields by cast/convert to the same data-type (or another one if needed). This way the definition of the “table”/”view” imported by LS contains all, originally not nullable fields, as nullable.
Very short example. Imagine Table Person as
Id int not null, PK
LastName nvarchar(50) not null,
FirstName nvarchar(50) null,
.
.
.
Your view’s SQL would be
select Id, CONVERT(nvarchar(50), LastName) as LastName, FirstName
from Person
Simple, dummy example just to display what I mean.
I feel I am re-inventing the wheel as this information was already out there, but in Greece we say “Επανάληψη μήτηρ μαθήσεως” or “Repetition is the mother of Learning” or something like that. Looks like we never learned much from this anyways…

P.S. After Yann's suggestion I have to note that actually this inferred primary key mechanism is Entity Framwork's native and not LightSwitch own behaviour. Although I had that in my mind I didn't make it clear here. I apologize for any missunderstanding and I thank Yann once more for the comment.

Monday, January 16, 2012

Save (is a pain in the) As

Currently being in the process of developing a business application, I came across an issue that looked harmless, but turned out to be what the title elegantly :-P implies.
Being very proud of what I can achieve in no time with LS, I had my product manager testing the application, when she ask me the simple: “How can I change something and save it as a new object with a new name?”. “It’s not implemented yet, but I am getting my hands on it right now and you will have it in no time”. What a typical developer answer!
“No time” turned out to be a full workday of experimenting trying to find out the best and most generic way to implement Save As functionality. Having an object being copied to another was something I had already implemented but I worked fine only on originals. Fetching an object to the client, modifying it somehow and then trying to copy to a new one, discard the changes of the original object and save the copy…well it was not a piece of cake, rather a pastry shop.
Creating a new object in a different instance of the dataworkspace and trying to copy ended up in a threading hell, as my object was not a simple one but having many one to many and many to many relations and threading had to be made “safe” to ensure consistency. Even if could manage to do it for the type of object requested by my product manager, the solution would be specific to this object and generalization would be a project on its own, with doubtful result.
Having the original and the copy on the same screen and context, made almost impossible to find a general way to discard changes made to the original (or any of the related objects) before saving the dataworkspace.
The final solution was rather naive, but totally generic and “LightSwitch” with only one drawback that I will mention at the end.
My datasource was an SQL Server based one. So I created a new one called myDataSourceNameCopy from the same database and also named all the entities EntityNameCopy (much better that EntityName1 suggested by default from LS. Now I had a myDataSourceName.Customer (for example) instance on my Customer Details screen and a myDataSourceNameCopy.CustomerCopy property waiting to be instantiated upon “Save As” command by the user.
A small parenthesis: one of the first contracts I designed and implemented for all the objects need was ICopyTo<TEntityType> where TEntityType : IEntityObject, which exposes a void CopyTo(TEntityType target). So Customer was already implementing ICopyTo<Customer> and what I had to do was implement ICopyTo<CustomerCopy> (and all referenced objects accordingly of course).
In order to by able to save from my screen both in myDataSourceName and myDataSourceNameCopy Ι took a look at this video tutorial. In the end when the used confirms the Save As, I save the changes in myDataSourceNameCopy, I discard the changes of myDataSourceName, close the screen, refresh the list of Customers (or whatever) and my “Saved As” Customer is there in the list of Customers ready to use. Well, I have to update two datasources every time my database changes but it’s a small price to pay, given that save as Is very important for my application.
The drawback is that I haven’t yet managed to figure out how this can be achieved with native LS datasources.
If anyone has implemented some other generic way to support Save As functionality and has to offer any ideas I would very much appreciate the comments.

Sunday, November 20, 2011

Auditing and Concurrency don’t mix (easily)…

In MSDN forums I came across a post addressing an issue I have also faced. Auditing fields can cause concurrency issues in LightSwitch (not exclusively).
In general basic auditing includes keeping track of when an entity was created/modified and by whom. I say basic auditing because auditing is in general much more than this.
Anyhow, this basic auditing mechanism is very widely implemented (it’s a way for developers to be able to easily find a user to blame for their own bugs :-p), so let’s see what this can cause and why in LightSwitch.
In the aforementioned post but also in this one, I have clearly stated that IMHO the best way to handle concurrency issues is using RIA Services. If you don’t, read what follows.
Normally in any application, updating the fields that implement Audit tracking would be a task completed in the business layer (or even Data layer in some cases and this could go as deep as a database trigger). So in LightSwitch the first place one would look into to put this logic would be EntityName_Inserting and EntityName_Updating  partial methods that run on the server. Which is right, but causes concurrency issues, since after saving the client instance of the entity is not updated by the changes made at the server and as soon as you try to save again this will cause concurrency error.
So, what can you do, apart from refreshing after every save which is not very appealing? Update at the client. Not appealing either but at least it can be done elegantly:
Let’s say all entities to implement auditing have 4 fields:
  • DateCreated
  • CreatedBy
  • DateModified
  • ModifiedBy
Add to the Common project a new interface called IAuditable like below:

namespace LightSwitchApplication{
    public interface IAuditable{
        DateTime DateCreated { get; set; }
        string CreatedBy { get; set; }
        DateTime DateModified { get; set; }
        string ModifiedBy { get; set; }
    }
}



Then, also in the common project, add a new class called EntityExtensions:
namespace LightSwitchApplication{
    public static class EntityExtensions{
        public static void Created<TEntityType>(this TEntityType entity, IUser user)
           where TEntityType: IAuditable{
           entity.DateCreated = entity.DateModified = DateTime.Now;
           entity.CreatedBy = enity.ModifiedBy = user.Name;
        }

        public static void Modified<TEntityType>(this TEntityType entity, IUser user)
           where TEntityType: IAuditable{
           entity.DateModified = DateTime.Now;
           entity.ModifiedBy = user.Name;
        }
    }
}



Now let’s suppose your entity’s name is Customer (imagination was never my strong point), the screen’s name is CustomerList and the query is called Customers.

First Viewing the Customer entity in designer click write code and make sure that:
partial class Customer : IAuditable{
}

Then at your screen’s saving method write this:
partial void CustomerList_Saving{
    foreach(Customer customer in this.DataworkSpace.ApplicationData.Details.GetChanges().AddedEntities.OfType<Customer>())
        customer.Created(this.Application.User);
    foreach(Customer customer in this.DataworkSpace.ApplicationData.Details.GetChanges().ModifiedEntities.OfType<Customer>())
        customer.Modified(this.Application.User);
}


This should do it. This way you can also easily move your logic to the server as the interface and extension class are defined in the Common project and they are also available to the server.
 



Thursday, October 6, 2011

Concurrent or fast? I’d rather have both…

Did you know that concurrency provided automatically by LightSwitch might cause performance issues that you cannot easily trace?
LightSwitch uses Entity Framework’s concurrency mechanisms to ensure data consistency while 2 or more users modify the same entries. You can read about it in detail and with examples in this great (as always) post by Michael Washington.
The thing, though, is that using native data sources or SQL server imported data sources, LightSwitch applies concurrency checking to all fields and you can do nothing about it. So, what is wrong about that? The price you have to pay in performance terms is small in exchange to ensuring concurrency, one would say. Unfortunately this is not always the case. Apart from functionality issues that can easily come up (entities with last modification fields for example), there is one special but not so uncommon case that can kill your performance. Large binary fields. Images is the most common example. Checking images byte against byte with every record updated for modifications, is something that, in most cases at least, no one wants.
As in many other cases, RIA comes to the rescue. With RIA services, importing your domain objects in an EF entity model you can fully control which fields are checked for concurrency and which are not. Not only this, but also concurrency exceptions are passed-through to LightSwitch and the resulting behavior is exactly the same as if you were using native or SQL server imported data sources. This is great don’t you think…Winking smile

Wednesday, October 5, 2011

Sort This, you Light of a Switch

Did you know that LightSwitch by default cannot sort or search against lookup columns?
Sad but true. The native Data Grid of LightSwitch cannot sort or search against lookup columns. The good news is that, as always with LightSwitch, you have an option. Which is not at all bad, by the way. In non-editable grids, that is in search or list-detail screens, you can use views. Yes, database views that is. Another solution would be calculated fields, but, although simpler, performance is poor IMHO.
Views? How do I create views in LightSwitch? Well, you don’t. You cannot have views in native data sources (at least I am not aware of some way). But you can import them. Either with a SQL Server data source from an existing database, or with RIA Services data source.
Having a view containing the id of the entity (it doesn’t have to be visible) you can use it to either open the default detail screen on click, or, in the list detail scenario, remove the detail group, add the original entity’s collection query and filter it based on the selected item of the view query, or have a <EntityCollection>_SinlgeOrDefault query and bind the parameter to the view query's selected item id column. Then add a detail group for this query. You might have implementation issues you should deal with, but hey, this is a tips blog.
P.S.1 If you use or planning to use 3rd party controls your commercial data grid might solve this problem without all of the above. But If you don’t…
P.S.2 The whole truth (and nothing but the truth) is that you might have issues correctly importing views from SQL Server (regarding primary key for example, have you fixed it yet George?) so if I have to be honest, I must say RIA is the best way to go…Winking smile

Friday, September 30, 2011

Large Small Medium Large?

Did you know that everything you design in a LightSwitch application (tables, screens, queries etc) is stored in a file called ApplicationDefinition.lsml?
LSML extension stands for the title of the post…no, I’m kidding of course. It stands for LightSwitch Markup Language. This file can be found in the folder <Project Path>\<Project Name>\Data.
Working in Logical View this is file is not visible (no files are visible in this view either way). Turning to File View you can see links to this file in all three projects Client, Common and Server. Notice they are links. The original file is not included directly in any project.
The reason there is only one file and all projects have link to it, is that it’s common to all of them and any change made to it should be available simultaneously to all projects.
The reason it’s not included to any project, in my humble opinion, is mainly because it’s not meant to be edited in any way. It could be included in the Common project for example as it IS common.This file is the product of all designer work done in LightSwitch. Even when you change the Theme, or Access Type properties of the application from the Properties of the project this change is stored in this file.
This is the reason also, that only ONE (or none) “<Project Name> Designer” window is available at any given time in your workspace. Because there IS only one such window displaying a different part of the ApplicationDefinition.lsml file every time you double-click a table or a form or whatever opens a designer window.
One tip for the end. When you plan a major change in your model (data design), especially if you are NOT using a native datasource, keep a backup of ApplicationDefinition.lsml. If you are using version control, check a version in, even temporarily. If not, keep a backup copy of the file. One day you might thank me for this advice…Winking smile

Thursday, September 29, 2011

Where are my tables (stored)?

Did you know that, when you create a native datasource in LightSwitch managing tables (entities) from the LightSwitch designer, the corresponding schema along with the data manipulated while debugging are stored in a SQL server database file set found in <ProjectName>\Bin\Data?
These database files are attached to the local instance of SQL 2008 Express. Visual Studio LightSwitch will install one if not found. The SQL server instance must be configured to allow user instances, as by default LightSwitch will attach the aforementioned files as a user instance. Along with your schema, default ASP.NET security schema is also found there.
The connection string compacting all the above can be found in the web.config file of the ServerGenerated project. If you don’t know what or where is this don’t worry we will talk about it in a next post. Just go ctrl+shift+F enter _IntrinsicData as the string to find and search in the entire solution. Please don’t touch. Generated, you know…Winking smile