Creating LightSpeed Context?

In the getting started with LightSpeed screencast I demonstrated the creation of a LightSpeed Context. A LightSpeed context is effectively a holder of information about one of your connections/databases. The norm is to use only one context because you’ve built an application that only talks to one database. LightSpeed does however support the ability to chat with several databases at once and therefore you can create several contexts.

In the video I had a property that when accessed created a LightSpeedContext() object and stored it in local scope for future use. The code looking something like this:

public static LightSpeedContext<ModelUnitOfWork> Context
{
  get
  {
    if (_context == null)
    {
      _context = new LightSpeedContext<ModelUnitOfWork>();
 
      // For illustrative purposes only -- better way shown below!
      _context.ConnectionString = LightSpeedContext.Default.ConnectionString;
      _context.PluralizeTableNames = LightSpeedContext.Default.PluralizeTableNames;
      _context.IdentityMethod = IdentityMethod.KeyTable;
    }
 
    return _context;
  }
}

This code showed that you could configure the context in code and read values off the default context that was configured in the .config file.

Hang on – we already have a context you say?

One thing that you may wonder about is why we couldn’t just use LightSpeedContext.Default? It is a ready-to-run LightSpeedContext after all.

The reason is that I wanted to use the LightSpeed LINQ API. The LightSpeedContext.Default is not strongly typed with the generic argument of and therefore would be missing the IQueryable collections for each of the entity types. The best way to demonstrate the difference to developers is to look at the intellisense output of the two types:

Strongly typed unit of work verse non typed

Notice that the only real difference is that there are collection properties of CartItems, Carts, Customers etc in typed unit of work.

Why have both? The strongly typed UoW is a convenience helper for the standard UoW. It is not providing anything you cannot do with the standard UoW, it’s just wrapping up some model-dependent boilerplate such as LINQ queries and stored procedure calls. The benefit of this is that at the expense of creating a strongly typed unit of work you get a lot of nice benefits for the rest of your development.

Now when we want to write LINQ queries we can write:

unitOfWork.Customers.Where(c => c.FirstName == "Chuck")

We couldn’t do that without the Customers collection.

Could we improve your example anyway?

Certainly! As I mentioned in the screencast, the implementation was just a quick setup to demonstrate how to get started. The way that you work with your context and unit of work is entirely dependent on your architecture.

In terms of reducing just the number of lines written in the simple example I used, we can throw away the awkward assignment of configuration values:

_context.ConnectionString = LightSpeedContext.Default.ConnectionString;
_context.PluralizeTableNames = LightSpeedContext.Default.PluralizeTableNames;
_context.IdentityMethod = IdentityMethod.KeyTable;

This was a tedious and redundant step but was important to show that you could configure the context in code. It is also handy when you just want to update a single value when debugging. We can however throw that all away with this code:

public static LightSpeedContext<ModelUnitOfWork> Context
{
  get
  {
    if (_context == null)
    {
      _context = new LightSpeedContext<ModelUnitOfWork>("default");
    }
 
    return _context;
  }
}

This would automatically apply the configuration from the .config file, picking up the configuration of the context named “default”, saving us time if we ever added a new configuration value in the .config file (for example, logging).

I hope that helps with understanding how the context can be manipulated, setup and used in different scenarios. As always, leave a comment if you have a question or feedback!

Tagged as LightSpeed

4 Responses to “Creating LightSpeed Context?”

  • That’s made things a lot clearer for me thanks.
    One question – how would you go about passing in the context name to your Repository class, assuming that you had set up say, “Dev” and “Live” connection strings in your App.config, which in turn were linked to LightSpeedContexts of “default” and “other” ?
    Or alternatively, if you just had “default” and wanted to change the connectionStringName at runtime by passing in either “Dev” or “Live” ?
    As I’m a bit new to C# I’m struggling with the syntax of passing in a parameter to the Context property…

  • You have a variety of options here (not necessarily a good thing I know):

    1. Create multiple entries in the lightSpeedContexts configuration section, each referring to a different connection string. E.g.:


    Then use these by passing in the appropriate string to the LightSpeedContext constructor:

    string configName = GetConfigNameFromSomewhere();
    _context = new LightSpeedContext(configName);

    The benefit of this is that it results in simpler, clearer code, and that it gives you full flexibility in setting up different configurations (e.g. if you want a configuration where caching is turned off, or your app is meant to run on either SQL Server or Oracle, so you want test configs for each of them). The downside is that in typical situations, where only the connection string is varying, there will likely be a lot of duplication between the “Dev”, “Test”, “Live” etc. config file entries. Also, if you have to include a password in the connection string (e.g. you are using something like Oracle which doesn’t have an “integrated security” option), you may not want the production password out there in a config file that any dev can look at (encrypted connection strings might help here but I suspect the unencrypted string would still be visible in the debugger).

    2. Have a single configuration file entry, and edit the connectionStringName setting when you copy the app.exe.config / web.config into another environment. Since you are presumably having to edit some config setting to signal which environment you’re in anyway, this shouldn’t be a major burden.

    3. Have a single configuration file entry, and initialise LightSpeedContext.ConnectionString explicitly in code from the section:

    string connStrName = GetConnStrNameFromSomewhere();
    _context = new LightSpeedContext(“default”);
    _context.ConnectionString = ConfigurationManager.ConnectionStrings[connStrName];

    The benefit of this is that you need specify model-level parameters only once. The downside is that you need to remember to explicitly load configuration-dependent parameters from code.

    My feeling is that the first option is probably the simplest but you would have to consider the security issues.

    Notice that in all three cases you should be using the last technique JD mentioned, i.e. new LightSpeedContext(configName), rather than copying properties one by one from LightSpeedContext.Default. LightSpeedContext.Default is essentially a wrapper for new LightSpeedContext(“default”): use it if you have only one config (or are using option 3) and want to save a few characters of typing. You should never use the technique of copying properties one by one from LightSpeedContext.Default, because if we add a new property, and you decide to make use of that property, you’ll have to remember to update your copying code as well as adding it to your config, and that’s twice the work!

    Regarding how to pass the context name into a Repository class, you could either:

    1. Externalise this: have your app code create the LightSpeedContext, and pass the LightSpeedContext object into the Repository class; or

    2. Pass the config entry name into the Repository class and have it use that when creating the LightSpeedContext.

    Hope this helps!

  • in the video (and article) you’ve mentioned that usually you are working with one database thus only 1 context is needed…

    If I am working with one database, that is ok, but what if I want to have 3 .lsmodel files, each with different entities/tables so my .lsmodel file/schema won’t be too big/complicated.

    Is it better to “separate database” into contexts or is it better (more efficient) to really have just one context of ALL MY TABLES in the database? I don’t know what is more memory intensive, but thinking about that you aren’t disposing context the first option is probably right one.

    I thought that when I am working with just small portion of my database at one time, there is no need for the .lsmodel to be so big.

    How about when I am using 2 databases, is there a chance to “connect” them? Having a membership database for example…

  • You can use the same LightSpeedContext for multiple .lsmodel files. A LightSpeedContext is basically a place to store connection strings and other configuration settings: it doesn’t care about the types of entity.

    However, if you are using LINQ, the way the designer generates strong-typed unit of work classes mitigates against this. If you have three .lsmodel files, A, B and C, then the designer will create three LINQ UOW types: AUnitOfWork, BUnitOfWork and CUnitOfWork, each with helper properties specific to its own .lsmodel. The way you would usually get an AUnitOfWork is to create a LightSpeedContext and call context.CreateUnitOfWork(). So in this case you *would* end up needing three contexts, one for each UOW type. But if you do this you also need to be careful that your business transactions don’t span .lsmodel files, because if you have an AUnitOfWork and a BUnitOfWork running simultaneously, they don’t know about each other. This shouldn’t be an issue because you can’t easily create relationships which span .lsmodel files, but just in case! (An alternative in this case is to create a “unified” LINQ helper class, e.g. ABCUnitOfWork, by hand.)

    Don’t worry about the memory cost of creating multiple LightSpeedContexts: it’s insignificant.

    No, you can’t “connect” two databases using LightSpeed, but you may be able to do so using features of the underlying database, e.g. if most of your entities are in database A but some are in database B, you might be able to create a view in database A which surfaces the entities from database B. Check your database documentation. You *can* have entities from different databases loaded simultaneously, but they will be in different units of work and will be saved separately; also you must be careful not to establish EntityHolder or EntityCollection relationships between them or LightSpeed may try to gather them into the same UOW.

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top