在MIX09大会上,Nigel Ellis提到了即将到来的新功能:开发者很快就能开发Azure托管的应用,并且可以使用传统的Transact SQL作为后端。虽然这项功能在本文撰写时尚未推出,但可以利用本地Azure开发环境来托管应用,并将其指向本地SQL Server实例,直到能够在线托管为止。
在开发这个应用的过程中,遇到了一些挑战,有的是因为Azure还处于测试阶段,有的则不是。将展示如何编写一个小型应用来展示新闻项目,这些新闻项目会不断更新。后端是一个SQL数据库,定期由Azure Worker Role更新,然后由Silverlight应用程序调用的Web服务读取,该应用程序本身托管在Azure WebRole上。
在开发这个应用时,将从后端开始,一直到构成客户端端的Silverlight应用程序。
根据SQL Data Services会议,无论是本地还是从SQL Data Services访问数据库,都将通过SQL Management Studio进行。一旦数据库创建完成,接下来就是创建存储新闻详情的表。
这个项目实际上是正在创建的一个更大项目的一部分。因此,想使用模式来逻辑上分隔数据库的不同部分。例如,这将允许一个数据库有两个名为'ledger'的表——一个在名为'Sales'的模式中,另一个在名为'Purchases'的模式中。将注意到,以下T/SQL示例中创建的所有数据库对象都以'NewsMashup'这个词开头。要创建这个模式,请对SQL数据库执行以下代码:
CREATE SCHEMA [NewsMashup] AUTHORIZATION [dbo];
创建一个表来存储将从中获取信息源的网站——这允许存储指向父站点的超链接。
创建一个表来存储从中获取新闻详情的信息源:
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
SET ANSI_PADDING ON;
GO
CREATE TABLE [NewsMashup].[Feeds](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Url] [varchar](max) COLLATE Latin1_General_CI_AS NOT NULL,
[Supplier] [bigint] NULL,
CONSTRAINT [PK_NewsFeeds] PRIMARY KEY CLUSTERED (
[Id] ASC
) WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF)
ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF;
GO
ALTER TABLE [NewsMashup].[Feeds] WITH CHECK ADD CONSTRAINT [FK_NewsFeeds_Supplier] FOREIGN KEY ([Supplier]) REFERENCES [NewsMashup].[Supplier] ([Id]);
GO
ALTER TABLE [NewsMashup].[Feeds] CHECK CONSTRAINT [FK_NewsFeeds_Supplier];
创建一个表来存储抓取到的新闻:
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
SET ANSI_PADDING ON;
GO
CREATE TABLE [NewsMashup].[Stories](
[Id] [bigint] NOT NULL,
[Headline] [varchar](max) COLLATE Latin1_General_CI_AS NOT NULL,
[Description] [varchar](max) COLLATE Latin1_General_CI_AS NOT NULL,
[Url] [varchar](max) COLLATE Latin1_General_CI_AS NOT NULL,
[Supplier] [bigint] NOT NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF;
将所有数据库查询放在存储过程中,可以获得许多优势。存储过程可以比内联代码更快,部分原因是数据库能够部分编译和优化查询。对于内联代码,这发生在执行时。对于显示新闻标题的应用程序,有四个存储过程;第一个是创建新闻:
ALTER PROCEDURE [NewsMashup].[CreateStory]
@Headline VarChar(Max),
@Description VarChar(Max),
@Url VarChar(Max),
@Supplier BigInt,
@PubDateValue BigInt
AS
Begin
Declare @Counter BigInt
Set @Counter = (
Select Count(*) As PreviousCounter
From NewsMashup.Stories
Where Url = @Url
)
If @Counter = 0
Begin
INSERT INTO NewsMashup.Stories
(Headline, Description, Url, Supplier, Id)
VALUES
(@Headline, @Description, @Url, @Supplier, @PubDateValue)
End
End
这个函数相当简单。首先检查链接是否已经添加到数据库中。如果没有,则添加新闻。接下来的两个过程都涉及到检索标题;需要两个——一个用于从数据库中检索最新的10个标题,另一个检索可能已经添加到数据库中的任何后续标题。这允许新标题在被获取时立即添加到显示中。
检索最新的10个标题:
ALTER PROCEDURE [NewsMashup].[RetrieveHeadlines]
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP (10) NewsMashup.Stories.Id,
NewsMashup.Stories.Headline,
NewsMashup.Stories.Description,
NewsMashup.Stories.Url,
NewsMashup.Supplier.HasDescription,
NewsMashup.Supplier.Name AS Supplier
FROM NewsMashup.Stories
INNER JOIN NewsMashup.Supplier
ON NewsMashup.Stories.Supplier = NewsMashup.Supplier.Id
ORDER BY NewsMashup.Stories.Id DESC
END
检索最新的新闻标题:
ALTER PROCEDURE [NewsMashup].[RetrieveHeadlines2]
@LatestHeadline BigInt
AS
BEGIN
SET NOCOUNT ON;
SELECT Id, Headline, Description, Url, Supplier
FROM NewsMashup.Stories
WHERE (Id > @LatestHeadline)
ORDER BY Id
END
ALTER PROCEDURE [NewsMashup].[RetrieveNewsFeeds]
AS
Begin
Select NewsMashup.Supplier.Id AS Supplier,
NewsMashup.Supplier.Name,
NewsMashup.Supplier.Url AS HomePage,
NewsMashup.Feeds.Url
From NewsMashup.Feeds
INNER JOIN NewsMashup.Supplier
ON NewsMashup.Feeds.Supplier = NewsMashup.Supplier.Id
Order By NewsMashup.Supplier.Name
End