Tải bản đầy đủ (.pdf) (10 trang)

Hướng dẫn học Microsoft SQL Server 2008 part 85 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (963.8 KB, 10 trang )

Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 802
Part V Data Connectivity
LINQ to Entities is more than a simple ORM tool. The ADO.NET Entity Framework and LINQ to Enti-
ties enable developers to work against a conceptual model that offers more flexible mapping, which pro-
vides the capability to utilize a wider degree of variance from the underlying data source.
What determines whether a project should use LINQ to SQL or LINQ to Entities/Entity Framework?
You should use LINQ to SQL when you want the following:
■ A rapid development cycle
■ An ORM solution and a 1:1 data/object model mapping
■ Optimized performance through stored procedures and compiled queries
■ To generate your own CLR classes versus using generated classes or deriving from base classes
In contrast, LINQ to Entities and the Entity Framework should be used when the following apply:
■ Your application targets different database engines in addition to Microsoft SQL Server
■ Your physical database structure could be significantly different from your object model. That
means you still want the benefits of an ORM but your classes may or may not map 1:1 with
your database schema.
■ You want to optimize performance through stored procedures and compiled queries
■ The LINQ query should work in a database vendor–neutral manner
■ You want to define application domain models to be used as the basis for a persistence layer
This section introduces LINQ to Entities and the Entity Framework and illustrates by example how easy
it is to create entities and query them using LINQ.
Everything needed to use LINQ to Entities and the Entity Framework is installed with Visual Studio
2008 SP1, which can be downloaded from the following location:
www.microsoft.com/downloads/details.aspx?FamilyId=FBEE1648-7106-44A7-
9649-6D9F6D58056E&displaylang=en
Creating and querying entities using LINQ
After installing the service pack, create a new Visual Studio C# Windows forms project. When the
project is loaded, add a new item to it. In the Add New Item dialog you will notice a new item in the
list of templates called ADO.NET Entity Data Model. This Entity Data Model provides the capability
to define domain models for an application. Select the ADO.NET Entity Data Model template, name it
AdventureWorks.edmx, and then click OK.


The Entity Data Model wizard begins. The first screen of the wizard provides the capability to define the
model contents. The model can be created from scratch, by selecting Empty Model, or generated from a
database, by selecting Generate from Database. By default, Generate from Database is selected, so ensure
that this option is selected and click Next.
The next step of the wizard defines the data connection. If a connection has previously been defined,
you can select it from the drop-down menu. If not, click the New Connection button and define a
802
www.getcoolebook.com
Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 803
LINQ 34
connection in the Connection Properties dialog. You are also asked at this step whether or not you want
to store sensitive connection information in the connection string. The connection string information
is stored in the application configuration file (
app.config) and is used by the ObjectContext
to connect to the database. Excluding the sensitive data (such as password information) from the
connection string requires that the information be set in the application code. Including the sensitive
data includes it in clear text in the
app.config. For production environments, it is recommended that
sensitive information be excluded from the connection string. For the purposes of this example, select
the option to include the sensitive information in the connection string.
Once the connection has been defined, click Next.
The next step of the wizard enables you to select the objects to be included in the model.
Objects such as tables, views, and stored procedures can be selected for inclusion. For this
example, select the
Person.Contact, HumanResources.Employee, Sales.Customer,and
Sales.SalesOrderHeader tables.
In addition, it is at this step of the wizard that the model namespace must be entered. It defaults to a
value, but it is good to verify that there is a value. By default, it takes the object name entered when the
ADO.NET Entity Data Model template was selected, which in this example is AdventureWorks, and then
adds the word ‘‘Model’’ to the end. Thus, the namespace should default to

AdventureWorksModel in
this example. Click Finish.
The wizard then builds the Entity Data Model based on the objects and selections in the wizard. When
it is complete, the Entity Data Model Designer opens in the Visual Studio IDE.
This process is very familiar to the LINQ to SQL example shown earlier. The difference is that with
LINQ to SQL, the database objects were added in the model after the designer was created. With the
Entity Framework, a wizard walks the developer through the steps of selecting which objects to include
in the model prior to creating the designer and model.
When the creation of the model is complete, a new node appears in the Solution Explorer. The
node is called
AdventureWorks.edmx and it has a child file, which is the Designer file called
AdventureWorks.Designer.cs.
Opening the .
edmx file opens the visual model designer that was created at the end of the wizard.
Our focus here is the
Designer.cs file. Opening that file displays some code that should look very
familiar. The
Designer.cs file contains the DataContext and all the necessary object mappings to
the database. For example, one of the first lines that should look familiar is the creation of a class that
inherits from the
DataContext:
public partial class AdventureWorksEntities :
global::System.Data.Objects.ObjectContext
Also different is the way tables are defined. Instead of applying the [Table] attribute, as done in LINQ
to SQL, this class inherits from the
EntityObject class, which is the base class for entity types that
are generated via the Entity Data Model tools, as shown here:
public partial class Employee :
global::System.Data.Objects.DataClasses.EntityObject
803

www.getcoolebook.com
Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 804
Part V Data Connectivity
The class is also attributed with several attributes, such as AdmEntityTypeAttribute, which indi-
cates that the class represents an entity type:
[global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute
(NamespaceName="AdventureWorksModel", Name="Employee")]
[global::System.Runtime.Serialization.DataContractAttribute
(IsReference=true)]
[global::System.Serializable()]
public partial class Employee :
global::System.Data.Objects.DataClasses.EntityObject
Also different is the way in which columns are defined and mapped. Instead of using the [Column]
attribute, as done in LINQ to SQL, columns are attributed with the EdmScalarProperty
Attribute
, which indicates that the property represents a scalar property:
[global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute
(EntityKeyProperty=true, IsNullable=false)]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public int EmployeeID
Another important item to look at is the set of relationship attributes. The EdmRelationship
Attribute
is used to define a relationship between two entity types (in this case, Contacts and
Employees) based on an association in the conception model:
[assembly: global::System.Data.Objects.DataClasses
.EdmRelationshipAttribute("AdventureWorksModel",
"FK_Employee_Contact_ContactID", "Contact",
global::System.Data.Metadata.Edm.RelationshipMultiplicity.One,
typeof(EF.Contact), "Employee",
global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many,

typeof(EF.Employee))]
With that background, it is time to focus on the front end. Open the form in design view and place a
list box and a button on the form. In the Click event of the button, add the following code:
AdventureWorksEntities awe = new AdventureWorksEntities();
var query =
from emp in awe.Contact
where emp.FirstName.StartsWith("S")
select emp;
foreach (var emp1 in query)
listBox1.Items.Add(emp1.LastName);
By now this code should look very familiar. It looks almost exactly like the LINQ to SQL code. The first
line creates an instance of the
AdventureWorksEntities class, followed by a LINQ query expres-
sion. The query is then iterated through and the results displayed in the list box.
804
www.getcoolebook.com
Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 805
LINQ 34
Compile the project and then run it. When the form displays, click the button. The list box will display
results, some of which are shown here:
Agcaoili
Jacobson
Altamirano
Alvarado
Appelbaum
Ayers

Querying multiple tables using LINQ to Entities and the Entity
Framework
This chapter closes with one last example that illustrates how to query multiple tables using LINQ to

Entities and the Entity Framework.
Place another button the form, and in the Click event add the following code:
AdventureWorksEntities awe = new AdventureWorksEntities();
var query =
from cus in awe.Customer
where cus.CustomerID == 2
select cus;
foreach (var cust in query)
{
listBox1.Items.Add(cust.CustomerID);
foreach (var ord in cust.SalesOrderHeader)
listBox1.Items.Add(" " + ord.OrderDate);
}
This example begins like the previous example, but the foreach loops are different. The LINQ query
returns a single record, where the CustomerID column in the
Sales table is 2. In the foreach loop,
that same CustomerID is written to the list box, and then a secondary loop loops through the orders for
that customerID.
Compile the application and run it. When the form displays, click button2. The list box displays the
CustomerID, but it does not display the sales order header rows for that customer. That is because the
query fetched the customer but it did not fetch the orders. Because the Entity Framework did not know
how the orders were going to be used, it did not want to automatically bring back information that was
not needed.
To fix that, the orders can be explicitly loaded for that specific customer by adding the following high-
lighted line of code to the first
foreach loop:
foreach (var cust in query)
{
listBox1.Items.Add(cust.CustomerID);
805

www.getcoolebook.com
Nielsen c34.tex V4 - 07/23/2009 1:56pm Page 806
Part V Data Connectivity
cust.SalesOrderHeader.Load();
foreach (var ord in cust.SalesOrderHeader)
listBox1.Items.Add(" " + ord.OrderDate);
}
When the foreach is executed, it will execute the query to return the customers, but not the orders.
When the
Load() statement is executed, it will create a separate query and return the orders for that
customer.
Run the project again and click button2. This time the list box will display the order dates for
CustomerID 2:
2
8/1/2002
11/1/2002
2/1/2003
5/1/2003
8/1/2003
11/1/2003
2/1/2004
5/1/2004
The preceding query is OK if the goal is to load only orders for some of the customers (for example,
when selecting a customer from a list), but in this case there exists a loop that will bring back every
order for every customer. Therefore, instead of executing multiple queries, a request can be made to
only pull back all of the orders with the customer in the initial query, as follows:
var query =
from cus in awe.Customer.Include("SalesOrderHeader")
where cus.CustomerID == 2
select cus;

When the application is run again, the results displayed in the text box are the same as the previous
query.
The goal of these two examples is to illustrate how easy LINQ to Entities and the Entity Framework
are to access SQL Server and query entities. With all that was shown in this chapter, it should be very
apparent how flexible yet powerful LINQ is for querying different data sources such as XML, DataSets,
and Entities.
Your homework assignment for this section is to create a new EF model. This time, however, in the wiz-
ard use an empty model, add one or more tables to it, and then write a LINQ query to query the data.
Summary
The purpose of this chapter was to provide an overview of LINQ and the different LINQ providers, and
show by example how powerful, flexible, and efficient they are in accessing the different types of data
sources.
In this chapter you learned what LINQ is and how to use LINQ to query data from different data
sources, such as XML, entities, and databases, using LINQ’s powerful standard query operators.
806
www.getcoolebook.com
Nielsen c35.tex V4 - 07/21/2009 2:10pm Page 807
Asynchronous Messaging
with Service Broker
IN THIS CHAPTER
Defining a work queue
Queuing messages
Managing conversations
S
ervice Broker is a powerful yet simple work queue system that can be used
to add asynchronous messaging and work queues to a database abstraction
layer to provide high scalability, and it is essential in any SOA data store
architecture.
If you’ve ever built a table to hold work to be done, such as orders to be
processed by a Materials Requirement Planning system, then you’ve built a work

queue. In one application Service Broker is just that — a high-performance,
wide-payload work queue integrated into SQL Server with DDL and monitoring
capabilities.
Service Broker can also be used to pass messages with guaranteed secure delivery
between work queues, which opens up a world of possibilities.
Because Service Broker is essentially just a SQL Server table, it includes all the
cool transactional and back-up capabilities inherent to SQL Server. This is what
sets Service Broker apart from other queuing technologies, such as Microsoft
Message Queuing (MSMQ).
The queue contains a single, wide column for the message body, which is OK
because the message will typically contain a single XML file or fragment or SOAP
message as the payload.
Service Broker is not enabled by default so the first specific step to working with
Service Broker is to turn it on using the
ALTER DATABASE command:
ALTER DATABASE AdventureWorks SET ENABLE_BROKER;
807
www.getcoolebook.com
Nielsen c35.tex V4 - 07/21/2009 2:10pm Page 808
Part V Data Connectivity
What’s New with Service Broker?
S
ervice Broker was introduced with much fanfare in SQL Server 2005. For SQL Server 2008, there are
a few slight enhancements: Conversations may now have an assigned priority; there are new DMVs for
monitoring Service Broker; there’s a new Service Broker Statistics Report; and Management Studio can now
auto-generate some Service Broker scripts.
Configuring a Message Queue
Service Broker uses a messaging or dialog metaphor, but there’s much more to Service Broker than just
the messages. The Service Broker objects must be defined in the following order:
1. Message types define the legal requirements of the message.

2. Contracts define the agreement between the initiating service and the target, including the
message type, the queue, and the services.
3. Queues hold the lists of messages.
4. Services communicate with the queue and either send or receive messages as the initiating
service or the target service, respectively.
Other than defining the message type as XML and naming the objects, there isn’t much complexity to
setting up a Service Broker database. That’s because the data definition language, or DDL, does all the
work; Service Broker is a message-agnostic work queue that’s serving as an infrastructure for the mes-
sages. There’s more work in placing messages on and taking messages off the queue.
Because Service Broker is integrated within SQL Server, the objects are created using the familiar create
DDL commands.
The first step in creating a Service Broker queue is to define a message type and a contract that uses that
message type:
CREATE MESSAGE TYPE HelloWorldMessage
VALIDATION = WELL_FORMED_XML ;
CREATE CONTRACT HelloWorldContract
( HelloWorldMessage SENT BY INITIATOR);
The initiator and target queues are also simply created using DDL:
CREATE QUEUE [dbo].[TargetQueue] ;
CREATE QUEUE [dbo].[InitiatorQueue] ;
Likewise, the initiator and target services are also defined using DDL. Both services are associated with a
queue, and the receiving, or target, service specifies that it can receive messages from a contract:
808
www.getcoolebook.com
Nielsen c35.tex V4 - 07/21/2009 2:10pm Page 809
Asynchronous Messaging with Service Broker 35
CREATE SERVICE InitiatorService
ON QUEUE [dbo].[InitiatorQueue];
GO
CREATE SERVICE TargetService

ON QUEUE [dbo].[TargetQueue]
(HelloWorldContract);
With the Service Broker objects created, you’ll be able to see them listed under the Object Explorer
Service Broker node.
Working with Conversations
With the Service Broker object created, messages can be placed into the queue or received from the
queue. Messages exist as part of a conversation that can be divided into conversation groups.
Sending a message to the queue
The following code creates a conversation using a conversationhandle GUID. The BEGIN
CONVERSATION
command opens the conversation, and the SEND command actually places the message
into the queue:
BEGIN TRANSACTION ;
DECLARE @message XML ;
SET @message = N‘<message>Hello, World!</message>’ ;
DECLARE @conversationHandle UNIQUEIDENTIFIER ;
BEGIN DIALOG CONVERSATION @conversationHandle
FROM SERVICE [InitiatorService]
TO SERVICE ‘TargetService’
ON CONTRACT [HelloWorldContract]
WITH ENCRYPTION = OFF, LIFETIME = 1000 ;
SEND ON CONVERSATION @conversationHandle
MESSAGE TYPE [HelloWorldMessage]
(@message) ;
END CONVERSATION @conversationHandle ;
COMMIT TRANSACTION ;
To view the message in the queue, select from the queue table as if it
were a normal relational table:
SELECT CAST(message_body as nvarchar(MAX)) from [dbo].[TargetQueue]
809

www.getcoolebook.com
Nielsen c35.tex V4 - 07/21/2009 2:10pm Page 810
Part V Data Connectivity
Receiving a message
The RECEIVE command will retrieve and remove the oldest message from the queue. Use RECEIVE
within a transaction so that if something goes wrong, the receive can be rolled back and the message
will still be in the queue. Service Broker is not a trigger that can code when a message is placed on the
queue; some code must run to extract the message. To accomplish this, Microsoft added a new option
to the
WAIT FOR command, enabling it to wait for a message in the queue. Without this option, the
code would have to run a loop to continuously check for a new message. The following routine within
a stored procedure will wait for a message and then receive the top message from the queue:
USE AdventureWorks ;
GO
Process all conversation groups.
WHILE (1 = 1)
BEGIN
DECLARE @conversation_handle UNIQUEIDENTIFIER,
@conversation_group_id UNIQUEIDENTIFIER,
@message_body XML,
@message_type_name NVARCHAR(128);
BEGIN TRANSACTION ;
Get next conversation group.
WAITFOR(
GET CONVERSATION GROUP @conversation_group_id FROM
[dbo].[TargetQueue]), TIMEOUT 500 ;
If there are no more conversation groups, roll back the
transaction and break out of the outermost WHILE loop.
IF @conversation_group_id IS NULL
BEGIN

ROLLBACK TRANSACTION ;
BREAK ;
END ;
Process all messages in the conversation group. Notice
that all processing occurs in the same transaction.
WHILE1=1
BEGIN
Receive the next message for the conversation group.
Notice that the receive statement includes a WHERE
clause to ensure that the messages received belong to
the same conversation group.
810
www.getcoolebook.com
Nielsen c35.tex V4 - 07/21/2009 2:10pm Page 811
Asynchronous Messaging with Service Broker 35
RECEIVE
TOP(1)
@conversation_handle = conversation_handle,
@message_type_name = message_type_name,
@message_body =
CASE
WHEN validation = ‘X’ THEN CAST(message_body AS XML)
ELSE CAST(N‘<none/>’ AS XML)
END
FROM [dbo].[TargetQueue]
WHERE conversation_group_id = @conversation_group_id ;
If there are no more messages, or an error occurred,
stop processing this conversation group.
IF @@ROWCOUNT=0OR@@ERROR <> 0 BREAK;
Show the information received.

SELECT ‘Conversation Group Id’ = @conversation_group_id,
‘Conversation Handle’ = @conversation_handle,
‘Message Type Name’ = @message_type_name,
‘Message Body’ = @message_body ;
If the message_type_name indicates that the message is
an error or an end dialog message, end the
conversation.
IF @message_type_name
=’ />OR @message_type_name
=’ />BEGIN
END CONVERSATION @conversation_handle ;
END ;
END; Process all messages in conversation group.
Commit the receive statements and the end conversation
statement.
COMMIT TRANSACTION ;
END ; Process all conversation groups.
use tempdb;;
811
www.getcoolebook.com

×