LINQ to SQL & WCF

Preview:

DESCRIPTION

LINQ to SQL & WCF. Using LINQ to SQL in n-Tiered architectures. Eric Phan. Solution Architect @ SSW Used LINQ to SQL since the early CTPs and Betas Used LINQ to SQL in a few large scale client applications Windows App Web Apps - PowerPoint PPT Presentation

Citation preview

LINQ to SQL & WCFUsing LINQ to SQL in n-Tiered architectures

Solution Architect @ SSW Used LINQ to SQL since the early CTPs and Betas Used LINQ to SQL in a few large scale client applications

Windows App Web Apps

In charge of Developer training and Architecture/Code reviews at SSW

http://ericphan.info

Eric Phan

Defining the tiers 3 tiered architecture with LINQ to SQL Working with WCF Some gotchas Some Tips

Agenda

What’s the worst application you have worked on? I was working on a Client project earlier…

But before I start…

They had a great architecture…

Database

ASP Website

60 tables with no relationships and keys It was crashing a lot 1000 ASP pages that managed their whole business

It had…

JobList.asp JobListA.asp JobListB.asp JobListForGregInAccounting.asp

There was a lot of ad hoc customizations

SQL Database to be cleaned up ASP to be rewritten with new functionality in ASP.NET ASP pages to be simplified Clearly defined workflow for their business processes Potentially later down the track they will have mobile

PDA or ruggedized laptops connecting to the system to access a subset of the functionality

They wanted…

Clean up the database Setup a good architecture with:

LINQ to SQL for data access Windows Workflow WCF for the business logic ASP.NET 3.5 Web Application Windows App [future release]

This is what we proposed

UIBusinessData

Northwind

Data Access

Data Access

Common Objects

LINQ to SQL DBML

WCF Service

s

WebUI

WinUI

Isn’t LINQ to SQL a 2 tiered technology?

How did we do it?

Where does LINQ to SQL fit in? The LINQ to SQL DBML consists of two main parts

DataContext – Data Access• e.g. NorthwindDataContext

Entities – objects representing data in your database• e.g. Customer, Order, Employee

It’s like your Data Adapters and Data Sets. The DataContext talks to the database and the Entities

just hold the data

By default it is 2 tiered I can call my data access from my Web using (var db = new NorthwindDataContext())

{ return db.Customers.ToList();}

2 Tiered?

Data

Northwind

Data Access/ClassesNorthwind.Common.Objects

DataContextEntities

UIData

Northwind

Data Access/ClassesNorthwind.Common.Objects

DataContextEntities

WebUI

WinUI

UIData

Northwind

Data Access/ClassesNorthwind.Common.Objects

DataContextEntities

WebUI

WinUI

UIData

Northwind

Data Access/ClassesNorthwind.Common.Objects

DataContextEntities

WebUI

WinUI

Business

Services

The entities should be shared across all the projects UI needs to know how to present the customer Business logic needs to know what to do with a

customer Data access needs to know how to get and update

a customer What about the DataContext?

It’s currently bundled with the entities Can we split it?

Where does LINQ to SQL fit in?

Has anyone tried?

Can we split it?

Create our own generic DataContext class in a new DataAccess project.

Create some methods in NorthwindData.cs to get and save data.

Make the generated DataContext class internal

So how do we separate our Data Access layer?

I would automatically separate the DataContext and Entities into two different projects or at least two different class files

You can achieve this through various techniques and code generators (e.g. generating XML using SQLMetal then using XSLT to create your Entity classes), but it’s not nice. This stuff really should be supported out of the box.

There are several projects out there that attempt to create this separation.

I find it easier just to create this generic DataContext

If I was the God of LINQ to SQL…

So how does our architecture look now?

UINorthwind.ServicesData

Northwind

Northwind.DataAccess

NorthwindData

Northwind.Common.Objects

Northwind.dbmlInternal DataContext

Entities

Services

WebUI

WinUI

Has anyone tried to use LINQ over WCF? Any problems? Any success stories?

Let’s talk business over WCF

Service Contracts Defines a set of contracts between the client and the

server so they know how to communicate [ServiceContract] – marks a class as visible to WCF clients [OperationContract] - marks a method as visible to WCF

clients [DataContract] – marks a class as transportable over WCF [DataMember] – marks a property on the class to serialize

WCF

Can easily configure how the service behaves E.g. listen over HTTP, TCP IP, UDP Enable reliable messages Enable encryption Enable security

Hosting via IIS Windows Service Console

WCF

Get a list of customers Delete some customers Update customer details View the orders a customer has made

Let’s talk business over WCF

Our WCF service is running

WCF Service Configurator

Data

Northwind

Data

Northwind

Northwind.Common.Objects

Northwind.dbmlwith Internal DataContext

Data

Northwind

Northwind.DataAccess

NorthwindData

Northwind.Common.Objects

Northwind.dbmlwith Internal DataContext

Northwind.ServicesData

Northwind

Northwind.DataAccess

NorthwindData

Northwind.Common.Objects

Northwind.dbmlwith Internal DataContext

Northwind.Service

s

Northwind.WebUI

Northwind.ServicesData

Northwind

Northwind.DataAccess

NorthwindData

Northwind.Common.Objects

Northwind.dbmlwith Internal DataContext

Northwind.Service

s

WebUI

WinUI

Make our client talk to the WCF services

Connecting the Client

Error #1 – Connection String

Where should I put it? A) Northwind.Common.Objects B) Northwind.DataAccess C) Northwind.Services D) Northwind.WebUI

Error #1 – Connection String

A:\ A) Northwind.Common.Objects B) Northwind.DataAccess C) Northwind.Services D) Northwind.WebUI

Let’s fix this and continue

Error #1 – Connection String

Error #2 – Underlying connection was closed

Has anyone come across this one? There’s not much details if you actually debug through

it

Error #2 – Underlying connection was closed

This is a WCF serialization issue Whenever you come across this error, 90% of the time

it’s because one of the objects/classes you are passing back from WCF can’t be serialized.

We need to make our LINQ classes serializable.

Error #2 – Underlying connection was closed

Serializable LINQ to SQL classes

[Table(Name="dbo.Customers")][DataContract()]public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged{

[Column(Storage="_CustomerID", DbType="NChar(5) NOT NULL", CanBeNull=false, IsPrimaryKey=true, UpdateCheck=UpdateCheck.Never)] [DataMember(Order=1)]

public string CustomerID

Serializable LINQ to SQL Classes

Error #3 – Maximum Message Size

Who wants to give up? Who’s hit this before? What did you do?

Error #3 – Message Size

Who wants to: A) Change the default size to the maximum

possible size B) Return less than 64K of data

Error #3 – Message Size

Who wants to: A) Change the default size to the maximum

possible size B) Return less than 64K of data

Error #3 – Message Size

This one is actually a very good issue to hit early Essentially what is happening here is that we’re doing

a SELECT * FROM Customers Does anyone have a problem with this? What if there were 100000 records?

Error #3 – Message Size

WCF is smart and doesn’t attempt to send any messages that are over a certain limit (by default it’s 64K)

Saves your end users from waiting a long time to load a page

Error #3 – Message Size

The right thing to do here is to change our query to use paging

Error #3 – Message Size

Message Size public List<Customer> GetCustomers(int pageIndex, int pageSize, out int totalCustomers) { using (var db = new NorthwindData()) { var customers = db.GetTable<Customer>(); totalCustomers = customers.Count();

var results = customers .Skip(pageIndex*pageSize) .Take(pageSize);

return results.ToList(); } }

Message Size

Creating a WCF service and hooking it up and these common issues Connection strings Serialization Message Size

What we saw

After this we will cover Deletes Updates Eager Loading

Lets take a break

Delete Customer Details Update

Lets add some more functionality

Delete

We solved it by deleting the references also You can also set Cascade deletes on in the database

Delete

Customer Details

Customer Details

Databinding through the UI against an object data source and our WCF service client

0 code in the UI

Customer Details

Should be easy…

Updates

Update Error #1

Fixed by adding Timestamp columns

Update Error #1

Update Error #2

Caused by the attach method just connecting the disconnected entity but not actually checking to see if there were any changes

As Modified parameter Fixed by using Context.Refresh()

Update Error #2

Cannot add an entity with a key that is already in use. Value of member 'TimeStamp' of an object of type

'Customer' changed. A member that is computed or generated by the

database cannot be changed.

Some other errors

A couple of strategies Timestamp column Reflection to replay changes Keep a copy of the original Use the Attach & Refresh method

(recommended)

LINQ to SQL - Updates

public void UpdateCustomer(Customer customer) { using (var db = new NorthwindData()) { db.GetTable<Customer>().Attach(customer, true); db.GetTable<Customer>().Context.Refresh(RefreshMode.KeepCurrentValues,

customer); db.Save(); } }

Updates - Attach and Refresh

It works!!!

Show the orders for a customer when you show the customer details

Lets do one more thing and load some orders

Use this when you need to bring along child objects with you

Saves you from doing another round trip Only works in one direction

Eager Loading with DataLoadOptions and LoadsWith

E.g. When viewing an order you can’t get it to eagerly load a Customer. order.Customer will be null order.CustomerID will have the CustomerID

Eager Loading with DataLoadOptions and LoadsWith

Why does it only work in one direction?• Remember the unidirectional serialization?• Uni means one

One way serialization

Requery for it as you will have access to the foreign keys

Create an aggregate class that will return what you need class OrderResult

{Customer customer;Order order;

}

What if I needed to access a parent object as well?

Make the generated DataContext internal Create your own generic one in DataAccess WCF

Serialization Gets – always page Updates – Attach & Refresh Eager Loading with DataLoadOptions and

LoadsWith<T>

Recap

We have used LINQ to SQL on several client projects Our developers love using it If you setup the architecture correctly then it is fine for

use Performance is faster than LINQ-to-Entities

http://www.thedatafarm.com/blog/2008/07/10/LookingAtEFPerformanceSomeSurprises.aspx

Is this ready?

We had a hard time looking at their existing system and couldn’t get a hold of the previous developer…

We eventually figured things out It was a 6 month project We had up to 8 developers working on the project It is currently in testing by the client

With our client from before

Rules to Better LINQ www.ssw.com.au/ssw/Standards/Rules/RulesToBetterLinq.a

spx Julie Lerman – Microsoft MVP, LINQ, EF guru

http://www.thedatafarm.com/blog/ Hooked on LINQ

http://www.hookedonlinq.com WCF Samples

http://msdn.microsoft.com/en-us/library/ms751514.aspx

Resources

EricPhan@ssw.com.au http://ericphan.info

Two things

Thank You!

Gateway Court Suite 10 81 - 91 Military Road Neutral Bay, Sydney NSW 2089 AUSTRALIA

ABN: 21 069 371 900

Phone: + 61 2 9953 3000 Fax: + 61 2 9953 3105

info@ssw.com.auwww.ssw.com.au