使用Apworks开发基于CQRS架构的应用程序(七):配置数据库
到目前为止,我们还未涉及任何数据库的配置工作。本章节将简单介绍基于Apworks的应用程序的数据库配置。在SQL Server中(目前的Apworks版本仅支持SQL Server)创建两个数据库:TinyLibraryEventDB和TinyLibraryQueryDB,然后分别执行如下SQL脚本:
- TinyLibraryEventDB
1: USE TinyLibraryEventDB;
2: /****** Object: Table [dbo].[DomainEvents] Script Date: 12/24/2010 20:27:20 ******/
3: IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DomainEvents]') AND type in (N'U'))
4: DROP TABLE [dbo].[DomainEvents]
5: GO
6: /****** Object: Table [dbo].[Snapshots] Script Date: 12/24/2010 20:27:20 ******/
7: IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Snapshots]') AND type in (N'U'))
8: DROP TABLE [dbo].[Snapshots]
9: GO
10: /****** Object: Table [dbo].[Snapshots] Script Date: 12/24/2010 20:27:20 ******/
11: SET ANSI_NULLS ON
12: GO
13: SET QUOTED_IDENTIFIER ON
14: GO
15: IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Snapshots]') AND type in (N'U'))
16: BEGIN
17: CREATE TABLE [dbo].[Snapshots](
18: [Id] [bigint] IDENTITY(1,1) NOT NULL,
19: [Timestamp] [datetime] NOT NULL,
20: [SnapshotData] [varbinary](max) NOT NULL,
21: [AggregateRootId] [bigint] NOT NULL,
22: [AggregateRootType] [nvarchar](max) COLLATE Chinese_PRC_CI_AS NOT NULL,
23: [SnapshotType] [nvarchar](max) COLLATE Chinese_PRC_CI_AS NOT NULL,
24: [Version] [bigint] NOT NULL,
25: [Branch] [bigint] NOT NULL,
26: CONSTRAINT [PK_Snapshots] PRIMARY KEY CLUSTERED
27: (
28: [Id] ASC
29: )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
30: )
31: END
32: GO
33: /****** Object: Table [dbo].[DomainEvents] Script Date: 12/24/2010 20:27:20 ******/
34: SET ANSI_NULLS ON
35: GO
36: SET QUOTED_IDENTIFIER ON
37: GO
38: IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DomainEvents]') AND type in (N'U'))
39: BEGIN
40: CREATE TABLE [dbo].[DomainEvents](
41: [Id] [bigint] IDENTITY(1,1) NOT NULL,
42: [AggregateRootId] [bigint] NOT NULL,
43: [AggregateRootType] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
44: [Timestamp] [datetime] NOT NULL,
45: [Version] [bigint] NOT NULL,
46: [Branch] [bigint] NOT NULL,
47: [TargetType] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
48: [Data] [varbinary](max) NOT NULL,
49: CONSTRAINT [PK_DomainEvents] PRIMARY KEY CLUSTERED
50: (
51: [Id] ASC
52: )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
53: )
54: END
55: GO
- TinyLibraryQueryDB
1: USE TinyLibraryQueryDB;
2: /****** Object: Table [dbo].[Books] Script Date: 12/14/2010 14:12:31 ******/
3: IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Books]') AND type in (N'U'))
4: DROP TABLE [dbo].[Books]
5: GO
6: /****** Object: Table [dbo].[Readers] Script Date: 12/14/2010 14:12:31 ******/
7: IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Readers]') AND type in (N'U'))
8: DROP TABLE [dbo].[Readers]
9: GO
10: /****** Object: Table [dbo].[Registrations] Script Date: 12/14/2010 14:12:31 ******/
11: IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Registrations]') AND type in (N'U'))
12: DROP TABLE [dbo].[Registrations]
13: GO
14: /****** Object: Table [dbo].[Registrations] Script Date: 12/14/2010 14:12:31 ******/
15: SET ANSI_NULLS ON
16: GO
17: SET QUOTED_IDENTIFIER ON
18: GO
19: IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Registrations]') AND type in (N'U'))
20: BEGIN
21: CREATE TABLE [dbo].[Registrations](
22: [Id] [bigint] IDENTITY(1,1) NOT NULL,
23: [BookId] [bigint] NOT NULL,
24: [ReaderId] [bigint] NOT NULL,
25: [ReaderName] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
26: [ReaderLoginName] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
27: [BookTitle] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
28: [BookPublisher] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
29: [BookPubDate] [datetime] NOT NULL,
30: [BookISBN] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
31: [BookPages] [int] NOT NULL,
32: [RegistrationDate] [datetime] NULL,
33: [DueDate] [datetime] NULL,
34: [ReturnedDate] [datetime] NULL,
35: [Returned] [bit] NULL,
36: CONSTRAINT [PK_Registrations] PRIMARY KEY CLUSTERED
37: (
38: [Id] ASC
39: )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
40: )
41: END
42: GO
43: /****** Object: Table [dbo].[Readers] Script Date: 12/14/2010 14:12:31 ******/
44: SET ANSI_NULLS ON
45: GO
46: SET QUOTED_IDENTIFIER ON
47: GO
48: IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Readers]') AND type in (N'U'))
49: BEGIN
50: CREATE TABLE [dbo].[Readers](
51: [Id] [bigint] IDENTITY(1,1) NOT NULL,
52: [LoginName] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
53: [Name] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
54: [AggregateRootId] [bigint] NOT NULL,
55: CONSTRAINT [PK_Readers] PRIMARY KEY CLUSTERED
56: (
57: [Id] ASC
58: )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
59: )
60: END
61: GO
62: /****** Object: Table [dbo].[Books] Script Date: 12/14/2010 14:12:31 ******/
63: SET ANSI_NULLS ON
64: GO
65: SET QUOTED_IDENTIFIER ON
66: GO
67: IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Books]') AND type in (N'U'))
68: BEGIN
69: CREATE TABLE [dbo].[Books](
70: [Id] [bigint] IDENTITY(1,1) NOT NULL,
71: [Title] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
72: [Publisher] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
73: [PubDate] [datetime] NOT NULL,
74: [ISBN] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
75: [Pages] [int] NOT NULL,
76: [Lent] [bit] NULL,
77: [AggregateRootId] [bigint] NOT NULL,
78: [LendTo] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
79: CONSTRAINT [PK_Books] PRIMARY KEY CLUSTERED
80: (
81: [Id] ASC
82: )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
83: )
84: END
85: GO
由于我们所使用的数据库系统是SQL Server,对于上面的TinyLibraryEventDB而言,它就是直接使用的Apworks应用开发框架中自带的SQL脚本。开发人员可以在Apworks的安装目录中找到该脚本文件。
就关系型数据库而言,我们需要一个额外的步骤去维护对象与数据表的映射关系。Apworks采用的是XML Storage Mapping Schema来维护这样的关系。
- 向TinyLibrary.Services项目添加一个新的XML文件,将其更名为DomainEventStorageMappings.xml,然后输入下面的内容
1: <?xml version="1.0" encoding="utf-8"?>
2: <StorageMappingSchema>
3: <DataTypes>
4: <DataType FullName="Apworks.Events.Storage.DomainEventDataObject" MapTo="DomainEvents">
5: <Properties>
6: <Property Name="Id" MapTo="Id" Identity="true" AutoGenerate="true"/>
7: </Properties>
8: </DataType>
9: <DataType FullName="Apworks.Events.Storage.SnapshotDataObject" MapTo="Snapshots">
10: <Properties>
11: <Property Name="Id" MapTo="Id" Identity="true" AutoGenerate="true"/>
12: </Properties>
13: </DataType>
14: </DataTypes>
15: </StorageMappingSchema>
- 向TinyLibrary.Services项目添加一个新的XML文件,将其更名为QueryObjectStorageMappings.xml,然后输入下面的内容
1: <?xml version="1.0" encoding="UTF-8"?>
2: <StorageMappingSchema>
3: <DataTypes>
4: <DataType FullName="TinyLibrary.QueryObjects.ReaderObject" MapTo="Readers">
5: <Properties>
6: <Property Name="Id" MapTo="Id" Identity="true" AutoGenerate="true"/>
7: </Properties>
8: </DataType>
9: <DataType FullName="TinyLibrary.QueryObjects.BookObject" MapTo="Books">
10: <Properties>
11: <Property Name="Id" MapTo="Id" Identity="true" AutoGenerate="true"/>
12: </Properties>
13: </DataType>
14: <DataType FullName="TinyLibrary.QueryObjects.RegistrationObject" MapTo="Registrations">
15: <Properties>
16: <Property Name="Id" MapTo="Id" Identity="true" AutoGenerate="true"/>
17: <Property Name="BookAggregateRootId" MapTo="BookId"/>
18: <Property Name="ReaderAggregateRootId" MapTo="ReaderId"/>
19: </Properties>
20: </DataType>
21: </DataTypes>
22: </StorageMappingSchema>
以下是这些XML文件的XSD结构,这个XSD Schema也被包含在Apworks应用开发框架的安装目录中。
1: <?xml version="1.0" encoding="UTF-8"?>
2: <!-- edited with XMLSpy v2009 (http://www.altova.com) by Administrator (EMBRACE) -->
3: <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
4: <xs:element name="StorageMappingSchema">
5: <xs:annotation>
6: <xs:documentation>Represents the schema for storage mapping.</xs:documentation>
7: </xs:annotation>
8: <xs:complexType>
9: <xs:sequence minOccurs="0">
10: <xs:element ref="DataTypes"/>
11: </xs:sequence>
12: </xs:complexType>
13: </xs:element>
14: <xs:element name="DataTypes">
15: <xs:complexType>
16: <xs:sequence minOccurs="0" maxOccurs="unbounded">
17: <xs:element ref="DataType"/>
18: </xs:sequence>
19: </xs:complexType>
20: </xs:element>
21: <xs:element name="DataType">
22: <xs:complexType>
23: <xs:sequence minOccurs="0">
24: <xs:element ref="Properties"/>
25: </xs:sequence>
26: <xs:attribute name="FullName" type="xs:string" use="required"/>
27: <xs:attribute name="MapTo" type="xs:string" use="required"/>
28: </xs:complexType>
29: </xs:element>
30: <xs:element name="Properties">
31: <xs:complexType>
32: <xs:sequence minOccurs="0" maxOccurs="unbounded">
33: <xs:element ref="Property"/>
34: </xs:sequence>
35: </xs:complexType>
36: </xs:element>
37: <xs:element name="Property">
38: <xs:complexType>
39: <xs:attribute name="Name" type="xs:string" use="required"/>
40: <xs:attribute name="MapTo" type="xs:string" use="required"/>
41: <xs:attribute name="Identity" type="xs:boolean" use="optional"/>
42: <xs:attribute name="AutoGenerate" type="xs:boolean" use="optional"/>
43: </xs:complexType>
44: </xs:element>
45: </xs:schema>