Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Saturday, 16 July 2011

0. Getting Started - Console app.

1. Quickstart – MVC2.  Model and querying.  Eager loading.

2. Deals – MVC3. Validation

3. Aptitude Test.  Webforms

4. TV Guide.  MVC2.  Caching.  Unit Testing

5. ATM.  Console app, WPF, WCF.

6. Film Festival.  MVC3. Silverlight and  RIA, Spacial Data Types, Logger

| | # 

image

Found it easier to copy the database to real SQLSERVER and not use attach databases as this was causing issues with permissions, and then copying of the database to the bin\debug folder, giving us multiple copies of the database.

  1. <add name="Development" connectionString="Data Source=.\;Initial Catalog=GettingStarted;Integrated Security=SSPI" />

DB Design is:

Pk’s called: Id  and not using Identity on the db side.  Rather using keytable.. this means that MovieId and CommentId will never be the same.

http://www.mindscapehq.com/blog/index.php/2007/08/26/lightspeed-identity-generation/  - good article on why KeyTable is good.

FK is MoveId

Looks like Convention over Configuration with a CreatedOn column!

image

Code that is useful!

    private static LightSpeedContext<ModelUnitOfWork> _context;
    static void Main(string[] args)
    {
      _context = new LightSpeedContext<ModelUnitOfWork>("Development");
      using (var uow = _context.CreateUnitOfWork())
      {
        if (uow.Movies.Count() == 0)

  <!-- This is required to tell .NET how to interpret the lightSpeedContexts section -->
  <configSections>
    <section name="lightSpeedContexts"
             type="Mindscape.LightSpeed.Configuration.LightSpeedConfigurationSection, Mindscape.LightSpeed" />
  </configSections>

  <!-- Here we configure the database connectivity and other configuration settings -->
  <lightSpeedContexts>
    <add name="Development"
         connectionStringName="Development"
         dataProvider="SqlServer2005"
         pluralizeTableNames="False" />
  </lightSpeedContexts>

  <!-- The standard connectionStrings section, referred to by lightSpeedContexts > connectionStringName -->
  <connectionStrings>
    <!--<add name="Development" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=True"/>-->
    <add name="Development" connectionString="Data Source=.\;Initial Catalog=GettingStarted;Integrated Security=SSPI" />
  </connectionStrings>
| | # 
# Friday, 08 April 2011
( LightSpeed | MVC )

Thanks to Sangsu for this http://stackoverflow.com/questions/5417220/change-ordering-in-mvc3-index-view

image

This is a simple implementation (not using a Grid):

public ActionResult Index(string sortColumn, bool? asc)
{
if (string.IsNullOrWhiteSpace(sortColumn))
sortColumn = "Name";

//if (!asc.HasValue)
// asc = true;

asc = asc ?? true; // coalesce does same as above


//if (sortColumn == "Name")
//{
// if (asc.Value)
// query = query.OrderBy(a => a.Name);
// else
// query = query.OrderByDescending(a => a.Name);
//}

//if (sortColumn == "IsEasternCountry")
//{
// if (asc.Value)
// query = query.OrderBy(a => a.IsEasternCountry);
// else
// query = query.OrderByDescending(a => a.IsEasternCountry);
//}

ViewBag.sortColumn = sortColumn;
ViewBag.asc = asc.Value;

// Use dynamic column names for sort order
Order order = Order.By(sortColumn);
if (!asc.Value)
order = order.Descending();

IList<Country> listOfCountries = uow.Find<Country>(new Query { Order = order});

return View(listOfCountries);
}


Notice the Lightspeed goodness.. have commented out the code it replaced! Thanks to Ivan http://stackoverflow.com/questions/5423728/mvccontrib-grid-sorting and the for coalesce tip above

View:

<table>
<tr>
<th></th>
<th>
@Html.ActionLinkWithColumnOrder("Name", "Index", (string)ViewBag.sortColumn, (bool)ViewBag.asc)
</th>
<th>
@Html.ActionLinkWithColumnOrder("IsEasternCountry", "Index", (string)ViewBag.sortColumn, (bool)ViewBag.asc)
</th>
<th>
IsWesternCountry
</th>
</tr>

@foreach (var item in Model) {
<tr>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
@Html.ActionLink("Details", "Details", new { id=item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
<td>
@item.Name
</td>
<td>
@item.IsEasternCountry
</td>
<td>
@item.IsWesternCountry
</td>
</tr>

and a helper:

public static class HtmlExtensions
{
public static MvcHtmlString ActionLinkWithColumnOrder(this HtmlHelper helper, string columnName, string action, string currentColumn, bool currentOrder)
{
object routeValues;
object htmlAttributes = null;
if (columnName == currentColumn)
{
routeValues = new { sortColumn = columnName, asc = !currentOrder };
htmlAttributes = new { @class = currentOrder ? "sort_asc" : "sort_desc" };
}
else
{
routeValues = new { sortColumn = columnName };
}

return helper.ActionLink(columnName, action, routeValues, htmlAttributes);
}
}

| | # 
# Wednesday, 16 March 2011
( LightSpeed | MVC )

Html.DropDownListFor – haven’t figured this out yet

http://stackoverflow.com/questions/1297399/populating-asp-net-mvc-dropdownlist

MvcScaffold does it – however a bit obscure

ViewBag

//
// GET: /People/Create

public ActionResult Create()
{
ViewBag.Countries = uow.Countries.OrderBy(c => c.Name).ToList();
var person = new Person();
return View(person);
}
 
and in the view:
 
<div class="editor-field">
@Html.DropDownList("CountryId",
new SelectList(ViewBag.Countries as System.Collections.IEnumerable,
"Id", "Name", Model.CountryId))
</div>

image
The FK relation is Person.CountryId
 
However in LightSpeed all the PK’s are called .Id
| | # 
( LightSpeed | MVC )

To make is easy to save, edit etc..

Found that the example in FilmFestival doesn’t work in MVC3

To get it compiling I used:

//var bindResult = bindingContext.ValueProvider[fieldName];
var bindResult = bindingContext.ValueProvider.GetValue(fieldName);

But then it failed when I added in:

EntityModelBinder.Register(typeof(MvcPvAdmin.Models.LightSpeedModel1UnitOfWork).Assembly);

in Global.asax  it bombed in BindModel.
| | # 
( LightSpeed | MVC )

A very simple example using People, full CRUD:

image

Identity is handled by the DB

image

public class PeopleController : Controller
{
LightSpeedContext<LightSpeedModel1UnitOfWork> _context = new LightSpeedContext<LightSpeedModel1UnitOfWork>("Default");

//
// GET: /People/
public ActionResult Index()
{
using (var uow = _context.CreateUnitOfWork())
{
return View(uow.People.ToList());
}
}

//
// GET: /People/Details/5

public ActionResult Details(int id)
{
using (var uow = _context.CreateUnitOfWork())
{
Person person = uow.People.Single(p => p.Id == id);
return View(person);
}
}

//
// GET: /People/Create

public ActionResult Create()
{
return View();
}

//
// POST: /People/Create

[HttpPost]
public ActionResult Create(Person person)
{
using (var uow = _context.CreateUnitOfWork())
{
if (!ModelState.IsValid)
return View(person);

uow.Add(person);
uow.SaveChanges();
return RedirectToAction("Index");
}
}

//
// GET: /People/Edit/5

public ActionResult Edit(int id)
{
using (var uow = _context.CreateUnitOfWork())
{
Person person = uow.People.Single(p => p.Id == id);
return View(person);
}
}

//
// POST: /People/Edit/5

[HttpPost]
public ActionResult Edit(Person person, int id)
{
if (ModelState.IsValid)
{
using (var uow = _context.CreateUnitOfWork())
{
Person personToUpdateFromDb = uow.People.Single(p => p.Id == id);

personToUpdateFromDb.Name = person.Name;
personToUpdateFromDb.Age = person.Age;
personToUpdateFromDb.CountryId = person.CountryId;

uow.SaveChanges();
}

return RedirectToAction("Index");
}
return RedirectToAction("Index");
}

//
// GET: /People/Delete/5

public ActionResult Delete(int id)
{
using (var uow = _context.CreateUnitOfWork())
{
Person person = uow.People.Single(p => p.Id == id);
return View(person);
}
}

//
// POST: /People/Delete/5

[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
using (var uow = _context.CreateUnitOfWork())
{
Person personToDelete = uow.People.Single(p => p.Id == id);
uow.Remove(personToDelete);
uow.SaveChanges();
}
return RedirectToAction("Index");
}

Validation

image

Name is not nullable, and must by less or equal to 5 in length

Age is nullable.

image

No code required to get this working.

Abstracting using statement

In Global.asax

internal static readonly LightSpeedContext<MvcPvAdmin.Models.LightSpeedModel1UnitOfWork> LightSpeedDataContext = new LightSpeedContext<MvcPvAdmin.Models.LightSpeedModel1UnitOfWork>("Default");

and a helper base class for controllers:

public class MvcPvAdminController : Controller
{
private const string UNIT_OF_WORK = "__UnitOfWork__";
private UnitOfWorkScopeBase<MvcPvAdmin.Models.LightSpeedModel1UnitOfWork> _unitOfWorkScope;

public UnitOfWorkScopeBase<MvcPvAdmin.Models.LightSpeedModel1UnitOfWork> UnitOfWorkScope
{
get
{
if (_unitOfWorkScope == null && System.Web.HttpContext.Current != null)
{
_unitOfWorkScope = System.Web.HttpContext.Current.Items[UNIT_OF_WORK] as PerRequestUnitOfWorkScope<MvcPvAdmin.Models.LightSpeedModel1UnitOfWork>;
}

if (_unitOfWorkScope == null)
{
_unitOfWorkScope = new PerRequestUnitOfWorkScope<MvcPvAdmin.Models.LightSpeedModel1UnitOfWork>(MvcApplication.LightSpeedDataContext);

if (System.Web.HttpContext.Current != null)
{
System.Web.HttpContext.Current.Items[UNIT_OF_WORK] = _unitOfWorkScope;
}
}

return _unitOfWorkScope;
}
}

protected MvcPvAdmin.Models.LightSpeedModel1UnitOfWork uow
{
get { return UnitOfWorkScope.Current; }
}

protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (_unitOfWorkScope != null)
{
_unitOfWorkScope.Dispose();
}

base.OnResultExecuted(filterContext);
}

public new void Dispose()
{
if (_unitOfWorkScope != null)
{
_unitOfWorkScope.Dispose();
}

base.Dispose();
}

so here is my newly updates Controller:

public class PeopleController : MvcPvAdminController
{
//
// GET: /People/
public ActionResult Index()
{
return View(uow.People.ToList());
}

//
// GET: /People/Details/5

public ActionResult Details(int id)
{
Person person = uow.People.Single(p => p.Id == id);
return View(person);
}

//
// GET: /People/Create

public ActionResult Create()
{
return View();
}

//
// POST: /People/Create

[HttpPost]
public ActionResult Create(Person person)
{
if (!ModelState.IsValid)
return View(person);

uow.Add(person);
uow.SaveChanges();
return RedirectToAction("Index");
}

//
// GET: /People/Edit/5

public ActionResult Edit(int id)
{
Person person = uow.People.Single(p => p.Id == id);
return View(person);
}

//
// POST: /People/Edit/5

[HttpPost]
public ActionResult Edit(Person person, int id)
{
if (!ModelState.IsValid)
return View(person);

Person personToUpdateFromDb = uow.People.Single(p => p.Id == id);

personToUpdateFromDb.Name = person.Name;
personToUpdateFromDb.Age = person.Age;
personToUpdateFromDb.CountryId = person.CountryId;

uow.SaveChanges();
return RedirectToAction("Index");
}

//
// GET: /People/Delete/5

public ActionResult Delete(int id)
{
Person person = uow.People.Single(p => p.Id == id);
return View(person);
}

//
// POST: /People/Delete/5

[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
Person personToDelete = uow.People.Single(p => p.Id == id);
uow.Remove(personToDelete);
uow.SaveChanges();
return RedirectToAction("Index");
}
}

| | # 
# Tuesday, 15 March 2011
( LightSpeed | MVC )

d/load 3.1 version of LightSpeed.  In the samples directory there is an MVC Film example.  Use vs2008.

http://www.mindscapehq.com/staff/jeremy/index.php/2009/03/aspnet-mvc-part1/

http://www.mindscapehq.com/staff/jeremy/index.php/2009/03/aspnet-mvc-part2/

http://www.mindscapehq.com/staff/jeremy/index.php/2009/03/aspnet-mvc-part3/ – setting up the site

http://www.mindscapehq.com/staff/jeremy/index.php/2009/03/aspnet-mvc-part4/ – model binding

Model namespace is:  Filmfestival.Model

Testing

Using NUnit.  A TestFixture base class to setup the testing.  TestDriven.NET as a test runner.

Managing the LightSpeed Unit of Work on a Per Request basis

Sets up a base class for managing.

Home View

Pass a ViewModel

image

public class HomePageViewModel
{
public IList<Film> Films { get; set; }
public IList<Location> Locations { get; set; }
public Film FeaturedFilm { get; set; }
}

then

IList<Film> films = UnitOfWork.Films.ToList().OrderBy(o => Guid.NewGuid()).Take(8).ToList();

HomePageViewModel model = new HomePageViewModel()
{
Locations = UnitOfWork.Locations.ToList(),
Films = films,
FeaturedFilm = films[0]
};

return View(model)

Model Binder

/home

/home/location/wellington

/home/location/christchurch

/film/new

ModelBinder is setup in global.asax

EntityModelBinder.Register(typeof(FilmFestival.Model.UnitOfWork).Assembly);

Validation

image

This is done server side here using the LS model.

| | # 
# Thursday, 04 November 2010

Using LightSpeed and turning on OC.

“The point of Optimistic Concurrency Checking is to prevent "Lost Updates". A lost update is where two users update the same data with one of the updates overwriting the other. The effect is as if one of the updates never occured at all - it was lost.

The benefit of Optimistic Concurrency Checking over Pessimistic Locking is that Optimistic Concurrency Checking does not require Database locks. Pessimistic Locking will use Database locks and this generally will reduce the concurrency the database can support.”

http://www.avaje.org/occ.html

We have overridden the default behaviour of LightSpeed to have a column in each table called Version.

| | # 
# Thursday, 28 October 2010

image

Here is the code:

protected void Page_Load(object sender, EventArgs e)
{
LightSpeedContext<NorthModelUnitOfWork> _context = new LightSpeedContext<NorthModelUnitOfWork>("Development");
_context.Logger = new TraceLogger();
using (var uow = _context.CreateUnitOfWork())
{
IList<Product> listOfProducts = uow.Find<Product>();
foreach (Product product in listOfProducts)
{
TextBox1.Text += product.ProductName + Environment.NewLine;
}
}
}

and here is the web.config:

<configSections>
<section name="lightSpeedContexts"
type="Mindscape.LightSpeed.Configuration.LightSpeedConfigurationSection, Mindscape.LightSpeed" />
</configSections>


<lightSpeedContexts>
<add name="Development"
dataProvider="SqlServer2008"
connectionStringName="Development" />
</lightSpeedContexts>


<connectionStrings>
<add name="Development"
connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=SSPI" />
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>

The .lsmodel is simply 1 table currently of Products from Northwind.

Abstract out

From: http://www.mindscape.co.nz/forums/Thread.aspx?PostID=8798

The above (a tightly scoped UnitOfWork) would work, however generally for web applications particularly when data binding you will find that you need to keep the UnitOfWork active for the duration of the web request so the ideal approach is to instantiate a UnitOfWork instance as required on a per request basis and then re-use that during the request and ensure it is disposed at the end of the request so the associated database connection can be closed etc.

The PerRequestUnitOfWorkScope class pretty much encapsulated that behavior, in that it creates a UnitOfWork instance as required and then stores that in HttpContext.Items for later re-use in that request. What it does not do however is dispose of the UnitOfWork, and you will need to do this yourself, either by explicitely disposing the PerRequestUnitOfWorkScope, or the UnitOfWork.

 

So in global.asax

public static LightSpeedContext<NorthModelUnitOfWork> _context = new LightSpeedContext<NorthModelUnitOfWork>("Development");
public static PerRequestUnitOfWorkScope<NorthModelUnitOfWork> Scope;

void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup


}

void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown

}

void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs

}

void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started

}

protected void Application_BeginRequest(object sender, EventArgs e)
{
_context.Logger = new TraceLogger();
Scope = new PerRequestUnitOfWorkScope<NorthModelUnitOfWork>(_context);
}

protected void Application_EndRequest(object sender, EventArgs e)
{
Scope.Dispose();
}

and now in webpage:

protected void Page_Load(object sender, EventArgs e)
{
var uow = Global.Scope.Current;
IList<Product> listOfProducts = uow.Find<Product>();
foreach (Product product in listOfProducts)
{
TextBox1.Text += product.ProductName + Environment.NewLine;
}
}

| | # 
# Wednesday, 27 October 2010
From the example DemoApp of EagerLoading (screencast example)
 
_context = new LightSpeedContext<ModelUnitOfWork>
{
ConnectionString = "Data Source=Store.db3;",
Logger = new TraceLogger(),
DataProvider = DataProvider.SQLite3,
PluralizeTableNames = false
};

the other logger is a consolelogger

| | # 

Great screencast on:

http://www.mindscape.co.nz/products/lightspeed/screencasts.aspx

Eager loading stops massive numbers of queries when you do something like this:

class Program
{
static void Main(string[] args)
{
foreach (Product product in Repository.Current.UnitOfWork.Products) //.WithAggregate("AllSkus")
{
Console.WriteLine(product.Name);

foreach (Sku sku in product.Skus)
{
Console.WriteLine(" - " + sku.DisplayName);
}
}

Console.ReadLine();
}
}
image

Either by using a named Aggregate above, which is a property of the relationship between Sku and Product

image

or just by turning eager loading on (but this will bring back all the skus)

image

This is all to stop massive numbers of queries of the db.

| | # 
# Friday, 22 October 2010

image

Interesting using services.. couldn’t get working **todo**

| | # 

image

Extension Method and Query syntax.

| | # 

image

Interesting.. WinForms.

| | # 

image

Architecture is (quoted):

The sample uses the standard ASP.NET page lifecycle architecture, but applies a seperation of concerns around the Model (LightSpeed Entities), Views (ASP.NET Pages). Process and application controller logic is handled within the code behind of each page, this includes any interaction'
with the LightSpeed unit of work.

The unit of work within LightSpeed is scoped around a single page request, and is completed at the end of each page as it becomes unloaded (refer: StorePage::Page_Unload)

Each View is based of a base class (StorePage) which provides common functionality.

Validation concerns are handled by using Validation support within LightSpeed and annotating our Model with the validation rules.

**can’t see the lsmodel in here**

| | # 

image

Using Sqlite (db3) database

Wires up events on: ToolStrip, ListBox and ListView

| | # 

image

MVC1 example using LS

Testing in nUnit.  Only a few tests.

Logging here to output console.. tried in VS2010 and it didn’t work as expected.

| | # 
# Thursday, 14 October 2010

I’ve been testing out this ORM from Mindscape – www.mindscape.co.nz

Here is App.config for both projects

<?xml version="1.0"?>
<configuration>

<configSections>
<section name="lightSpeedContexts"
type="Mindscape.LightSpeed.Configuration.LightSpeedConfigurationSection, Mindscape.LightSpeed" />
</configSections>

<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>

<connectionStrings>
<add name="Dev" connectionString="data source=.\sqlexpress;Integrated Security=SSPI;initial catalog=LSTest" providerName="System.Data.SqlClient"/>
</connectionStrings>

<lightSpeedContexts>
<add name="default"
connectionStringName="Dev"
dataProvider="SqlServer2005"/>
</lightSpeedContexts>

</configuration>

had to remember to turn identity property on Country to:  IdentityColumn

as I’m making the database keep track of its new identities ie auto inc.  In this example I’m using ints.

Unit Test Code (thanks PeterJ)

[TestMethod]
public void Can_CRUD_Countries()
{
LightSpeedContext context = new LightSpeedContext("default");
using (var uow = context.CreateUnitOfWork())
{
// get all
var results = uow.Find<Country>();
int count = results.Count();

Assert.IsNotNull(results, "results are null");

Country country = new Country { Name = "hhh" };
uow.Add(country);
uow.SaveChanges();
Assert.IsTrue(country.Id > 0, "id not updated");

// get all again - should have 1 more
results = uow.Find<Country>();
Assert.IsTrue(results.Count == count + 1, "should be 1 more record and there isn't");

// edit the record
country.IsWesternCountry = true;
uow.SaveChanges();

// read it back and double check
country = uow.FindById<Country>(country.Id);
Assert.IsNotNull(country, "could not find country");

Assert.IsNotNull(country.IsWesternCountry, "oh boy, update didnt work");

//// and finally delete
uow.Remove(country);
uow.SaveChanges();

// get all again - should have 1 more
results = uow.Find<Country>();
Assert.IsTrue(results.Count == count, "should be 1 less record and there isn't");
}

}

| | #