On the 13th of May I presented a talk to the VIC.NET Dev SIG on the topic of ADO.NET for Silverlight. The talk was one day after the release of Visual Studio 2008 SP1 Beta1 so I promised to post the PowerPoint and demos later when I had them working with SP1. Silverlight 2 Beta 2 still hasn't been released but I have the first couple of demos re-done. You can download these from the following links:
Later (soon J) when Silverlight 2 Beta 2 is released I'll add the WinForms and Silverlight client demos
Demo 1 - Entity Framework
The first demo was creating an Entity Model from a database. The database (Flights) is very simple. There are only 3 tables:
These tables are mapped directly into three EntitySets in the Entity Model but additionally for a bit of bling I added a direct many-to-many relationship between Passenger and Flight and an Inherited Entity AvailableFlight. The discriminator for AvailableFlight is the IsAvailableFlight column from the Flight Table.
There are a couple of points to note here:
The discriminator Column for the Inheritance relationship (IsAvailableFlight) can't be an identity or computed column. Trying to use a computed discriminator gives you a validation error:
Error 2016: Condition cannot be specified for Column member <column> because it is marked with a 'Computed' or 'Identity' StoreGeneratedPattern
But IsAvailableFlight makes more sense as a derivative of MaxSeats – AllocatedSeats so I cheated and implemented a trigger on the Flight Table that recalculates IsAvailableFlight and RemainingSeats whenever MaxSeats or AllocatedSeats are updated.
CREATE
TRIGGER [dbo].[Flight_Updated]
ON [dbo].[Flight]
AFTER
INSERT,UPDATE
AS
BEGIN
SET
NOCOUNT
ON;
IF
UPDATE(MaxSeats)
OR
UPDATE(AllocatedSeats)
UPDATE dbo.Flight SET RemainingSeats = ins.MaxSeats - ins.AllocatedSeats,
IsAvailableFlight =
CONVERT(bit,
(CASE
WHEN
(ins.MaxSeats - ins.AllocatedSeats > 0)
THEN 1 ELSE 0 END))
FROM inserted ins
WHERE Flight.FlightID = ins.FlightID
END
- There is already a relationship in the model between Passenger and Flight via the two one to-many Associations and the Seat EntitySet. If you try to add the additional many-to-many Association again using Seat as the mapping table you get one of the following errors for each association:
Error 3034: Problem in Mapping Fragment(s) starting at line(s) <lines>: Data loss is possible. These two partitions are equal in the storage model but not in the conceptual model. Check that both ends of the AssociationSet are mapped to the corresponding columns.
I fixed this by adding a view of the Seat table to the database and using the view as the mapping table for the PassengerFlight many-to-many association.
As part of the EF demo I also showed some funky LINQ to Entities queries that made use of the Inherited Entity. That was from Readify's new PRO.NET 3.5 course so I can't post that code here. We will explore some of the inheritance options in the Client-Side code in later Demos.
Demo 2 – ADO.NET Data Services
The second demo was exposing the Entity Model using ADO.NET Data Services. This is very simple – you just add an ADO.NET Data Service to the project and then change a couple of things in the template class, first the parent template so the class definition becomes:
public
class
FlightsDataService : DataService<FlightsModel.FlightsEntities>
Then set some security rules. In this case I have set them as follows:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.SetEntitySetAccessRule("Seat", EntitySetRights.WriteAppend | EntitySetRights.AllRead);
config.SetEntitySetAccessRule("Passenger", EntitySetRights.WriteAppend | EntitySetRights.AllRead);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
The DataService does not have any ServiceOperations available so the permissive "ServiceOperationRights.All" doesn't really cause any problems. The Entity Set Access rules allow anyone read only access to all the EntitySets and allow new Passengers and Seats to be added – the significance of this will become clearer in later demos.
I then demoed a number of REST queries in a browser. If you want to try this yourself you will have to turn off the feed reading view in IE so you can see the raw data.
When you browse to the service you see a list of the supported entities. http://endintiers.com/FlightsService/FlightsDataService.svc
If you want a list say of the Passenger entity set you can browse to: http://endintiers.com/FlightsService/FlightsDataService.svc/Passenger
To retrieve a particular Passenger you need to use the EntityKey, try: http://endintiers.com/FlightsService/FlightsDataService.svc/Passenger(1)
All the flights for Passenger 2
http://endintiers.com/FlightsService/FlightsDataService.svc/Passenger(2)/Flights
All the passengers on Passenger 2's Flight 1
http://endintiers.com/FlightsService/FlightsDataService.svc/Passenger(2)/Flights(1)/Passengers
Only AvailableFlights
http://endintiers.com/FlightsService/FlightsDataService.svc/Flight?$filter=isof('FlightsModel.AvailableFlight')
Passengers whose FirstName contains Ch
http://endintiers.com/FlightsService/FlightsDataService.svc/Passenger?$filter=contains(FirstName,'Ch')
You can start to see the power of this URI-based query syntax. Any Entity can be accessed via HTTP: retrieved (GET), inserted (POST), deleted (DELETE) or updated (PUT). Client libraries are available for .NET, AJAX and Silverlight.
If you were awake you may have noticed that those links above actually do something...there is a demo service running on my Blog server....
Coming soon: The WinForms Client and the Silverlight Client (when Silverlight 2 Beta 2 finally drops).