Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LightSpeed 4 Gettings Started

Avatar for jakescott jakescott
September 27, 2011

LightSpeed 4 Gettings Started

Avatar for jakescott

jakescott

September 27, 2011
Tweet

More Decks by jakescott

Other Decks in Programming

Transcript

  1. Getting Started with LightSpeed 2 At its worst business logic

    can be very complex. Rules and logic describe many different cases and slants of behaviour, and it’s this complexity that objects were designed to work with. A Domain Model creates a web of interconnected objects, where each object represents some meaningful individual, whether as large as a corporation or as small as a single line on an order form. Martin Fowler Contents Getting Started with LightSpeed ............................................................................................................. 3 About LightSpeed ................................................................................................................................ 4 Objects and Databases .................................................................................................................... 4 LightSpeed and Object-Relational Mapping ................................................................................... 4 Getting Started ........................................................................................................................................ 6 Building Your First Domain Model .................................................................................................. 6 Modelling ........................................................................................................................................ 7 Designing the Model using the Visual Studio Designer .................................................................. 8 Code Generation ........................................................................................................................... 10 Conventions .................................................................................................................................. 11 LightSpeedContext and UnitOfWork ............................................................................................ 11 Scoping your UnitOfWork ............................................................................................................. 14 Querying ........................................................................................................................................ 14 Creating and Updating Entities ..................................................................................................... 15 Next Steps ............................................................................................................................................. 18 About This Book .................................................................................................................................... 19
  2. Getting Started with LightSpeed 3 Getting Started with LightSpeed Welcome

    to the Quick Start walkthrough for LightSpeed. This document will introduce you to the core concepts, classes and techniques of LightSpeed. We will look at how to create a domain model, load your domain data and make changes to that data and save it back to your database. In this walkthrough, we will be using the LightSpeed Visual Studio Designer which takes care of most routine tasks for you so you will need to have installed LightSpeed prior to embarking on this document.
  3. Getting Started with LightSpeed 4 About LightSpeed LightSpeed is a

    domain modelling and object to relational mapping framework for the .NET Framework. Simply put, it allows you to design the business entities around which your system will be formed and handles the retrieval and persistence of those entities allowing you to concentrate on developing the solution at hand. LightSpeed has been designed around the idea of a domain model and the philosophy is centred on the following guiding principles:  Convention over configuration.  Support idiomatic .NET domain models: validation, data binding, change notification etc.  Highly usable API and low barrier to entry.  Encapsulate and encourage best practice patterns: session per request, Unit of Work etc.  Testability built in.  Small, lightweight and fast. LightSpeed provides a number of runtime components and an integrated Visual Studio designer which allows you to get productive quickly and helps you integrate with some of the other useful frameworks available as part of the standard Microsoft .NET development offering. Objects and Databases When you analyse a business domain, you are creating a conceptual model of that domain. You identify the entities in that domain, the state and behaviour of those entities, and their relationships. However, at some point, that conceptual model has to be translated into a concrete software implementation. In fact, in almost all practical business applications, it has to be translated into (at least) two concrete software implementations: one implementation in terms of programming entities (objects), and one in terms of a relational database. This is where things start getting tedious and potentially complex, because the object and relational worlds use quite different representations. At best, the code to query the database, load objects and save them again is laborious and repetitive. This is where object-relational mapping comes in. An object-relational mapper, or ORM, takes care of the mechanical details of translating between the worlds of programmatic objects and relational data. The ORM figures out how to load and save objects, using either explicit instructions such as an XML configuration file, or its own heuristics, or a combination of the two. This lets you, the programmer, focus on writing your business logic and application functionality against the domain model (in its object representation), without having to worry about the details of the relational representation. LightSpeed and Object-Relational Mapping LightSpeed as an object-relational mapper leans strongly towards using its own heuristics to figure out how to load and save data: that is, it works out how objects and properties map to tables and
  4. Getting Started with LightSpeed 5 columns without having to be

    told. This is known as convention over configuration. The immediate practical benefit of this is that we don’t need to write rules telling the ORM how to load and save objects. The impact is that it requires us to keep our object design and our database design reasonably in sync. However, even this has a higher-level benefit: it guides us towards a consistent data design that reflects the business domain.
  5. Getting Started with LightSpeed 6 Getting Started Let’s get started

    with LightSpeed by:  Building up a simple domain model  Running some queries  Making changes to entities This example will assume you are building using the C# language and are targeting a .NET 3.5 based solution. The designer experience is the same for both Visual Studio 2008 and Visual Studio 2010 but the screenshots depict a Visual Studio 2010 environment. Building Your First Domain Model To create your first domain model, start by creating a new project within Visual Studio. For the purposes of this example we will create a ConsoleApplication but the steps described are common to any type of application you might be building. The next step is to create a LightSpeed model. To do this, Add a New Item to the project and then select LightSpeed Model from the list of available item templates. Enter an appropriate name to describe the domain for this model, or if you are only likely to use a single domain model for the entire application the standard is to name this Model. In this example we will create our model using the name Model, which will generate a new file called Model.lsmodel within our project.
  6. Getting Started with LightSpeed 7 Note: If you are using

    Visual Studio 2010, you may see this warning dialog pop up after creating a new model file in a Console Application or Windows Application project. The reason for this is that by default Visual Studio 2010 creates these project types targeting the .NET 4.0 Client Profile. As LightSpeed is an external dependency you need to target the standard .NET 4.0 Framework profile to use it, so you will need to follow through the instructions shown on the dialog to switch the profile setting over. Modelling LightSpeed supports several ways in which you can elaborate your domain model. You can either start by describing your domain model prior to creating your database (this is known as Model First), or by starting with an existing database and using that to create your initial model (this is known as Database First) or by hand crafting your entities using code (this is known as Code First). We find that most users of LightSpeed start by designing their model first and then creating the database using tools within the LightSpeed designer. For the purposes of this example, we will be designing a simple which has 2 entities, a Movie and a Comment. There is a relationship between Movie and Comment in that a movie may have one or more comments about it. We will model this in LightSpeed using a Model First approach which means we will use the LightSpeed designer to describe our model and then commit this to a database. You could equally achieve the same goal by using the Database First or Code First approaches but we find that typically users prefer the Model First approach.
  7. Getting Started with LightSpeed 8 Designing the Model using the

    Visual Studio Designer Designing your domain model using the Model First approach is simple using the LightSpeed Design Surface. To get started, double click on the Model.lsmodel file which opens up the design surface in Visual Studio. Expanding the Toolbox pane gives you access to the objects which you can use to model with. We will start by dragging on 2 entity shapes, one for each of the domain entities we described above. As you drag these on, you can can set the properties for the Entity underneath the properties pane, and you can also start adding your entity properties by right clicking and selecting “Add > Entity Property”. It is a good idea to keep your Properties pane pinned within Visual Studio while performing your modelling as the context will change depending on what you have selected. You are likely to want to change a number of aspects particularly for entity properties so this saves you some time. The next step is to model the relationships between the entities. Drag a one to many association shape on to Movie and then link it to Comment, this will set up the one to many relationship between these entities.
  8. Getting Started with LightSpeed 9 Once we have completed modelling,

    we will want to save our schema to the database. To do this we first need to describe the type of database we are dealing with and supply an appropriate connection string so that we can connect to that database. These are entered underneath the properties for the model. Expand the Properties window and enter the Connection String accordingly.
  9. Getting Started with LightSpeed 10 Once you have this set

    up, you can right click on the diagram surface and select “Update Database”. This will cause LightSpeed to check the existing database and diff between what it finds and what we have modelled to determine what changes need to be committed from our model back to the database. Here is an example of applying our recently created model to an empty database: The act of creating the table will create the table with any associated properties, and with any associated relationships to other tables. If you wish to save a copy of the SQL script which it has generated (this is an exact copy of the statements which will be sent to the database) then check the Log SQL box. You may have noticed that there is also an “Update from Source” option. You would use this to refresh your model with any changes from the database. This also allows you to model iteratively in both directions. Code Generation By using the LightSpeed Designer you are actually generating code for the classes represented by your models. All LightSpeed domain models are ultimately represented using either C# or VB.NET code. The design surface provides the productivity boost and convenience in creating these,
  10. Getting Started with LightSpeed 11 however you can craft your

    own models by using the appropriate conventions and attributes to describe your intent. If you expand the Model.lsmodel node within your project you will find a Model.cs file has been generated and this contains the code definition for the entities we have created. This file will be regenerated every time you save using the design surface. If you wish to extend these classes with custom behaviour or additional fields and properties you can create a partial class to one side of the generated code and add your extensions there. This ensures that your changes will not be overwritten when regeneration occurs. Conventions LightSpeed is an opinionated framework and as such there are a number of conventions that LightSpeed relies on. It is worth taking a few minutes to examine the output of the LightSpeed Designers code generation as reviewing the source code for a LightSpeed entity will help highlight to you some of these conventions. Here are the key conventions you should expect to find: 1. Every domain entity has a base class of Entity<T>, and more specifically in the example it will be Entity<int>. This base class provides a lot of the heavy lifting for allowing your entities to be data bindable, to have validation and to track changes effectively. The type T refers to the type of your primary key column (the Id property) and you will want to set this accordingly. 2. Every domain entity had an Id property. This is the primary key of the entity and is not directly assignable. LightSpeed manages the assignment of this value using an identity strategy and uses this Id when specifying foreign key relationships. If you have an existing database where the primary key column has a different name you will notice that there will be a Column attribute attached which will specify the name of the column in the database. 3. LightSpeed has a backing field for each entity property. When LightSpeed looks at what properties an entity actually contains, it does so by looking at all of the fields on the entity rather than the properties. This allows you to describe other properties as part of your domain model which are not stored in the database. If you wish to have additional fields on the entity you can do so by appending the [Transient] attribute to the fields which should be ignored by LightSpeed. 4. Every domain entity has been generated as partial so you can extend them as required. LightSpeedContext and UnitOfWork When using LightSpeed you will be interacting with a UnitOfWork to perform your queries and persist any changes to your entities. The UnitOfWork is scoping pattern which is wrapped around the idea of a business transaction within your application. As described by Martin Fowler, the Unit Of Work pattern “maintains a list of
  11. Getting Started with LightSpeed 12 objects affected by a business

    transaction and coordinates the writing out of changes and the resolution of concurrency problems.” A unit of work in LightSpeed is primarily two things: 1. A database connection 2. An Identity Map of references to the entities currently in memory. Typically, you will create a unit of work per thread (in a Windows application) or a unit of work per request (in a Web application). However, you can create multiple units of work within the same thread or request if you need to do so. A unit of work should not be shared between threads as it encapsulates non-thread-safe resources such as database connections. A unit of work is designed to be short-lived: typically you will create the unit of work, load and/or modify some data, save changes if required, and then dispose of the unit of work. In LightSpeed you will instantiate your IUnitOfWork instances by using a LightSpeedContext. The LightSpeedContext manages the configuration required to connect to a database and any additional LightSpeed behaviours that are required to work with your schema such as pluralisation of table names. As entities are loaded from the database through the IUnitOfWork.Find method, and new entities are added through the IUnitOfWork.Add method, they become tracked by this unit of work. If any of the entities are modified they will be automatically persisted during the next save operation. To save the changes in a unit of work, call IUnitOfWork.SaveChanges. To dispose of a unit of work and free associated resources, call IUnitOfWork.Dispose. Configuration for the LightSpeedContext can either be specified via the properties of the context object, or using application configuration. The suggested approach is to use application configuration and to assist with this we have a helper which is built in to the LightSpeed designer which will provide you with the configuration blocks you will need. To use this, right click on the design surface and select “Get Started”. This will bring up a dialog with the configuration block information and example code for instantiating your LightSpeedContext instance.
  12. Getting Started with LightSpeed 13 So in this case our

    configuration block would look similar to this. Sample configuration block generated by the Getting Started context menu option <configSections> <section name="lightSpeedContexts" type="Mindscape.LightSpeed.Configuration.LightSpeedConfigurationSection, Mindscape.LightSpeed" /> </configSections> <lightSpeedContexts> <!-- TODO: Check pluralizeTableNames setting --> <!-- TODO: Add identityMethod="..." if not using KeyTable --> <add name="Development" connectionStringName="Development" dataProvider="SqlServer2005" pluralizeTableNames="False" /> </lightSpeedContexts> <connectionStrings> <add name="Development" connectionString="Data Source=.;Initial Catalog=GettingStarted;Integrated Security=True;Pooling=False"/> </connectionStrings>
  13. Getting Started with LightSpeed 14 Scoping Your Unit of Work

    The UnitOfWork has been designed to be short lived and is ideally scoped around a single set of logical operations. It may however be more sensible for the application you are building to scope the UnitOfWork more widely; for example, within a Web Application you would generally want to scope it on a per-request basis. LightSpeed can automatically create and dispose units of work for you based on the common patterns mentioned above. To do this, instead of creating a unit of work explicitly using LightSpeedContext.CreateUnitOfWork, create a UnitOfWorkScopeBase and access the UnitOfWorkScopeBase.Current property. For the per-request approach described above, LightSpeed provides a built-in implementation of UnitOfWorkScopeBase, named PerRequestUnitOfWorkScope<TUnitOfWork>. Querying LightSpeed provides both a native query API and a LINQ provider to allow you to express queries to retrieve entities. Initially we would recommend you focus on using the LINQ provider since this will be the most familiar to you. If you are targeting the .NET 3.5 or 4.0 frameworks then the LightSpeed Designer will add code generation for a strongly typed UnitOfWork class which provides a property for each entity type which gives you an IQueryable for each entity collection. This gives you a starting point to write LINQ queries using LightSpeed. For example, for the model which we generated earlier a class called ModelUnitOfWork. Here is the associated code which was generated for it. [System.CodeDom.Compiler.GeneratedCode("LightSpeedModelGenerator", "1.0.0.0")] public partial class ModelUnitOfWork : Mindscape.LightSpeed.UnitOfWork { public System.Linq.IQueryable<Comment> Comments { get { return this.Query<Comment>(); } } public System.Linq.IQueryable<Movie> Movies { get { return this.Query<Movie>(); } } } We can create new instances of our strongly typed UnitOfWork by using the following syntax. You will notice that we are specifying the type of our UnitOfWork as a generic argument to the LightSpeedContext and specifying a configuration name for that context as the argument for its constructor. That configuration name matches up to the a section in our configuration that we created earlier using the Getting Started context menu option.
  14. Getting Started with LightSpeed 15 private static LightSpeedContext<ModelUnitOfWork> _context; //

    initialize the context _context = new LightSpeedContext<ModelUnitOfWork>("Development"); // create a unit of work using (var uow = _context.CreateUnitOfWork()) { } Once we have created our typed unit of work we can start writing our queries. Here is an example of a LINQ query we might write using our UnitOfWork instance. Querying the database foreach (var movie in uow.Movies.OrderBy(m => m.CreatedOn)) { Console.WriteLine("{0} - comment count: {1}", movie.Title, movie.Comments.Count()); } LightSpeed’s LINQ provider has been written as a translation engine over the native querying API, so any query which can be expressed in the native query API can also be expressed in LINQ (and vice versa). Because the LightSpeed LINQ provider acts as a translator for you to express queries in the LightSpeed query API if you try to express a query which could not otherwise be written using the query API then a NotSupportedException will be thrown. Similarly LINQ allows for an open ended number of possible queries to be expressed, however not all queries may be sensible or even possible given the nuances of your particular data provider. Please review the sections on Database Providers and Querying in the LightSpeed User Guide to understand more about this. Creating and Updating Entities As described above, when you create and manipulate entities with LightSpeed, you do so within the scope of a business transaction which is known as a unit of work, represented by the IUnitOfWork interface or UnitOfWork class. To create an entity, you simply instantiate it as with any standard .NET object and assign values to the applicable parameters. You can then Add it to a UnitOfWork by calling UnitOfWork.Add(entity).
  15. Getting Started with LightSpeed 16 Here is an example from

    our earlier model. Creating a new entity and adding it to the unit of work var movie1 = new Movie(); movie1.Title = "Hackers (1995)"; movie1.Description = "A young boy is arrested by the US Secret Service for writing a computer virus and is banned from using a computer until his 18th birthday."; uow.Add(movie1); uow.SaveChanges(); If you are dealing with an entity which has relationships to other entities, these can either be assigned directly to the associated property, or will be automatically assigned by LightSpeed if you add the entity to a child collection of an existing LightSpeed entity (this also means you don’t actually need to call UnitOfWork.Add either). Adding an entity to the unit of work by association var comment1 = new Comment(); comment1.Body = "Best hackers movie ever!"; comment1.PostedBy = "John-Daniel Trask"; comment1.Movie = movie1; uow.SaveChanges(); // comment1 has been added to the UnitOfWork by association To update an entity, you must first fetch it by using a query. Once you have an instance of the entity available you can update data on the properties of the entity. LightSpeed implements the standard .NET INotifyPropertyChanged event and will raise this when a property has been updated. LightSpeed will also track if an entity has been modified during its lifecycle within the scope of a UnitOfWork so that it only sends updates for entities which have actually been modified during the course of the UnitOfWork. Updating an existing entity foreach (var comment in uow.Comments) { comment.PostedBy = "A dodgy spammer"; } uow.SaveChanges(); To remove an entity, you can call UnitOfWork.Remove(entity) to mark it as deleted. If the entity has dependent children they will also be deleted otherwise any objects which have an association to the
  16. Getting Started with LightSpeed 17 entity which is being deleted

    will be unwired which means the entity would be removed from an child collections it belongs to, and any direct associations held to the entity will be set to null. This has the effect that removing an entity may actually cause several entities to be updated in the process. Deleting an existing entity foreach (var movie in uow.Movies) { uow.Remove(movie); } uow.SaveChanges(); Note: If you need to remove many entities at once you should look at using the alternative overload of UnitOfWork.Remove(query) which allows you to pass in a query object to scope what should be removed. If you are using this overload please be aware that this means that no entities will be loaded into the UnitOfWork as a result (this is actually one of the good reasons to use this approach – to avoid unnecessary entity hydration if you are only intending to immediately remove the entity). Note also that you must still call SaveChanges to commit the deletion. When making changes, they are not immediately saved to the database. You explicitly flush any pending changes by calling UnitOfWork.SaveChanges() which will determine all of the insert/update/delete statements which need to be sent (in the appropriate ordering based on the structure of the database) and will issue the statements accordingly. Note: If the database provider supports command batching then statements will be issued as a batch of changes. There are certain operations such as Insert statements where the identity strategy for the entity is IdentityColumn which cannot be batched and will always be issued as individual statements.
  17. Getting Started with LightSpeed 18 Next Steps Now that you

    have built a simple application using LightSpeed, take a look at the samples and review the LightSpeed User Guide for more information about the product. We would recommend reviewing the Quick Start sample first as this builds on the model we have elaborated in this guide and extends it to be part of a working web store application. We have provided a sample which contains the model and code highlighted in this document as part of the LightSpeed installation. You can find the solution named “Getting Started” underneath the LightSpeed >> Samples folder in your start menu.
  18. Getting Started with LightSpeed 19 About This Book This book

    walks you through the process of creating a simple LightSpeed application. You should read it in conjunction with these other books:  LightSpeed User Guide, which provides conceptual documentation and guidance information.  LightSpeed API Reference, which provides detailed documentation for all LightSpeed classes and members You can access these books from the Mindscape > LightSpeed folder on the Start menu.