Slide deck - EricPhan.net

Download Report

Transcript Slide deck - EricPhan.net

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

In charge of Developer training and Architecture/Code reviews at
SSW

http://ericphan.info
Agenda

Defining the tiers

3 tiered architecture with LINQ to SQL

Working with WCF

Some gotchas

Some Tips
But before I start…

What’s the worst application you have worked on?

I was working on a Client project earlier…
They had a great architecture…
Database
ASP
Website
It had…

60 tables with no relationships and keys

It was crashing a lot

1000 ASP pages that managed their whole business
There was a lot of ad hoc
customizations

JobList.asp

JobListA.asp

JobListB.asp

JobListForGregInAccounting.asp
They wanted…

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
This is what we proposed

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]
Data
Data Access
Business
UI
WebUI
Northwind
Data Access
WCF
Services
WinUI
Common Objects
LINQ to SQL DBML
How did we do it?

Isn’t LINQ to SQL a 2 tiered technology?
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
2 Tiered?

By default it is 2 tiered

I can call my data access from my Web

using (var db = new NorthwindDataContext())
{
return db.Customers.ToList();
}
Data
Northwind
Data Access/Classes
Northwind.Common.Objects
DataContext
Entities
Data
UI
WebUI
WinUI
Northwind
Data Access/Classes
Northwind.Common.Objects
DataContext
Entities
Data
UI
WebUI
WinUI
Northwind
Data Access/Classes
Northwind.Common.Objects
DataContext
Entities
Data
Business
UI
WebUI
Services
WinUI
Northwind
Data Access/Classes
Northwind.Common.Objects
DataContext
Entities
Where does LINQ to SQL fit in?

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?
Can we split it?

Has anyone tried?
So how do we separate our Data
Access layer?

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
If I was the God of LINQ to SQL…

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
So how does our architecture look
now?
Data
Northwind.DataAccess
Northwind.Services
UI
WebUI
Northwind
NorthwindData
Services
WinUI
Northwind.Common.Objects
Northwind.dbml
Internal DataContext
Entities
Let’s talk business over WCF

Has anyone tried to use LINQ over WCF?

Any problems?

Any success stories?
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
Let’s talk business over WCF

Get a list of customers

Delete some customers

Update customer details

View the orders a customer has made
Our WCF service is running
WCF Service Configurator
Data
Northwind
Data
Northwind
Northwind.Common.Objects
Northwind.dbml
with Internal DataContext
Data
Northwind
Northwind.DataAccess
NorthwindData
Northwind.Common.Objects
Northwind.dbml
with Internal DataContext
Data
Northwind
Northwind.DataAccess
Northwind.Services
NorthwindData
Northwind.
Services
Northwind.Common.Objects
Northwind.dbml
with Internal DataContext
Data
Northwind.DataAccess
Northwind.Services
Northwind.WebUI
WebUI
Northwind
NorthwindData
Northwind.
Services
WinUI
Northwind.Common.Objects
Northwind.dbml
with Internal DataContext
Connecting the Client

Make our client talk to the WCF services
Error #1 – Connection String
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 #2 – Underlying connection was
closed
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.
Serializable LINQ to SQL classes
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
Error #3 – Maximum Message Size
Error #3 – 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
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
What we saw

Creating a WCF service and hooking it up and these common
issues



Connection strings
Serialization
Message Size
Lets take a break

After this we will cover



Deletes
Updates
Eager Loading
Lets add some more functionality

Delete

Customer Details

Update
Delete
Delete

We solved it by deleting the references also

You can also set Cascade deletes on in the database 
Customer Details
Customer Details
Customer Details

Databinding through the UI against an object data source and
our WCF service client

0 code in the UI
Updates

Should be easy…
Update Error #1
Update Error #1

Fixed by adding Timestamp columns
Update Error #2
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()
Some other errors

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.
LINQ to SQL - Updates

A couple of strategies




Timestamp column
Reflection to replay changes
Keep a copy of the original
Use the Attach & Refresh method (recommended)
Updates - Attach and Refresh


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();
}


}
It works!!!
Lets do one more thing and load
some orders

Show the orders for a customer when you show the customer
details
Eager Loading with DataLoadOptions
and LoadsWith

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
Why does it only work in
one direction?
•
Remember the unidirectional
serialization?
•
Uni means one

One way serialization
What if I needed to access a parent
object as well?

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;
}
Recap

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>
Is this ready?

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/LookingAtEF
PerformanceSomeSurprises.aspx
With our client from before

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
Resources

Rules to Better LINQ


Julie Lerman – Microsoft MVP, LINQ, EF guru


http://www.thedatafarm.com/blog/
Hooked on LINQ


www.ssw.com.au/ssw/Standards/Rules/RulesToBetterLinq.aspx
http://www.hookedonlinq.com
WCF Samples

http://msdn.microsoft.com/en-us/library/ms751514.aspx
Two things

[email protected]

http://ericphan.info
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
[email protected]
www.ssw.com.au