19
Getting Started with LightSpeed 1

Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

Getting Started with LightSpeed 1

Page 2: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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 Unit of Work ............................................................................................................ 14

Querying ........................................................................................................................................ 14

Creating and Updating Entities ..................................................................................................... 15

Next Steps ............................................................................................................................................. 18

About This Book .................................................................................................................................... 19

Page 3: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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.

Page 4: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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

Page 5: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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.

Page 6: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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, Visual Studio 2010 and

Visual Studio 2012 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.

Page 7: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

Getting Started with LightSpeed 7

Note: If you are using Visual Studio 2010 or Visual Studio 2012, 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 and 2012 creates these project types

targeting the .NET 4.0 or .NET 4.5 Client Profile. As LightSpeed is an external dependency you need

to target the standard .NET 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.

Page 8: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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” (or you can press the ‘Insert’ key – this will create a property after the one that is currently

selected).

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.

Page 9: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

Getting Started with LightSpeed 9

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.

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.

Page 10: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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,

however you can craft your own models by using the appropriate conventions and attributes to

describe your intent.

Page 11: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

Getting Started with LightSpeed 11

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

objects affected by a business transaction and coordinates the writing out of changes and the

resolution of concurrency problems.”

Page 12: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

Getting Started with LightSpeed 12

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.

Page 13: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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>

Page 14: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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.

Page 15: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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).

Page 16: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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

Page 17: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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.

Page 18: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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.

Page 19: Getting Started with LightSpeed 1 · Getting Started with LightSpeed 5 columns without having to be told. This is known as convention over configuration.The immediate practical benefit

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.