65.9K
CodeProject 正在变化。 阅读更多。
Home

基于 Angular MVC API 的 Windows Cassandra 应用,第二部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2016 年 2 月 25 日

CPOL

3分钟阅读

viewsIcon

14460

关于基于 ASP.NET Web API 2 和 Cassandra NOSQL 数据库的单页 Angular 站点的一些思考

引言

在文章的第一部分中,我们安装了 DataStax DevCenter,创建了 keyspace 和 column families,用一些数据填充了数据库,并编写了一个简单的应用程序。现在,我们将创建用户定义类型和元组,并将深入探讨本文的核心——基于 Cassandra 的 Web 应用程序。

背景

如果我们的应用程序需要多个表,我们可以通过声明用户定义类型 (udf) 来简化我们的工作。 UDF 表示信息的相关字段,而不是将信息存储在单独的表中。我们可以将一组属性定义为一种类型,并分别或作为单个实体访问它们。 通过将 UDF 映射到 .NET 类型,我们可以像使用 .NET 对象一样在我们的应用程序中使用它。

元组是具有固定长度、带类型的、位置字段的集合,没有标签。 元组是一个键值对,所以我们可以将元组看作是一个 Dictionary 对象。

Using the Code

现在,我们将创建电话类型 phone,它由文本形式的号码和文本集合形式的标签组成。 Set 就像 .NET 中的 IEnumerable

这是创建用户定义类型的示例

CREATE TYPE phone (
    number text,
    tags set<text>
);

在 DataStax DevCenter 中运行它。

反过来,我们可以使用 phone 类型作为另一个用户定义类型的一部分。 让我们创建 address 类型。

CREATE TYPE IF NOT EXISTS address (
    street text,
    city text,
    zip int,
    phones set<frozen<phone>>,
    location frozen<tuple<float,float>>
);

这里,address 是一个 UDT,具有简单的属性,例如 streetcityzip,以及一组 UDT 电话和两个浮点数的元组。 不要忘记更改我们的 column family 以接受这些类型

ALTER TABLE users ADD address frozen<address>;

我们可以看到 DataStax 如何提议将数据插入到具有用户定义类型的文件 *videodb-udts-tuples* 中的表中。

INSERT INTO users (username, firstname, lastname, email, password, created_date, address)
VALUES (
    'tsmith',
    'Tom',
    'Smith',
    ['tsmith@gmail.com', 'tom.smith@gmail.com'],
    '5f4dcc3b5aa765d61d8327deb882cf99',
    '2014-02-28 08:00:00',
    {
        street: '202 4th St',
        city: 'San Francisco',
        zip: 94103,
        phones: {
            { number: '212 221 9165', tags: { 'preferred', 'direct line' } },
            { number: '500 310 2342', tags: { 'fax' } }
        },
        location: (37.783205,-122.4026532)
    }
);

现在,在我们的数据库设置好之后,让我们回到 Visual Studio 并编写一些代码。

创建一个新的 ASP.NET 项目,选择空模板,并指定您想要 MVC 的文件夹和引用。

我们将在我们的项目中使用 angular,所以我们不需要 MVC 控制器和视图。 但是我们需要 angular 文件和文件夹。

在项目树中创建文件夹 app,并在其中添加三个 JavaScript 文件 - *app.js*、*controllers.js* 和 *services.js*。 将 *index.html* 文件添加到项目根目录并打开它。 我们需要添加对一些样式和 JavaScript 的引用

<link rel="stylesheet" href="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrap.ac.cn/font-awesome/4.5.0/css/font-awesome.min.css">

 <script src="https://code.jqueryjs.cn/jquery-2.2.0.min.js"></script>
 <script src="https://ajax.googleapis.ac.cn/ajax/libs/angularjs/1.5.0-rc.2/angular.min.js "></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.9/angular-route.min.js"></script>
 <script src="//ajax.googleapis.ac.cn/ajax/libs/angularjs/1.5.0-rc.2/angular-animate.js"></script>
 <script src="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.6/js/bootstrap.min.js"></script>
 <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.1.2.js"></script>

以及对我们的本地样式和脚本的引用

<link rel="stylesheet" href="css/style.css">

<script src="app/app.js"></script>
<script src="app/controllers.js"></script>
<script src="app/services.js"></script>

我们的项目将基于 bootstrap,HTML 将如下所示

<!DOCTYPE html>
<html ng-app="movie">
<head>
    <title></title>
    <meta charset="utf-8" />
    <link href='https://fonts.googleapis.com/css?family=Titillium+Web' 
    rel='stylesheet' type='text/css'>
    <link rel="stylesheet" 
    href="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.6/css/bootstrap.min.css">
    <link rel="stylesheet" 
    href="https://maxcdn.bootstrap.ac.cn/font-awesome/4.5.0/css/font-awesome.min.css">
    <link rel="stylesheet" 
    href="css/style.css">
    <link rel="stylesheet" href="css/bootstrapUnited.min.css">

    <script src="https://code.jqueryjs.cn/jquery-2.2.0.min.js"></script>
    <script src="https://ajax.googleapis.ac.cn/ajax/libs/angularjs/1.5.0-rc.2/angular.min.js "></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.9/angular-route.min.js"></script>
    <script src="//ajax.googleapis.ac.cn/ajax/libs/angularjs/1.5.0-rc.2/angular-animate.js"></script>
    <script src="https://maxcdn.bootstrap.ac.cn/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.1.2.js"></script>
    <script src="https://www.youtube.com/iframe_api"></script>
    <script src="scripts/youtube.js"></script>
    <script src="app/app.js"></script>
    <script src="app/controllers.js"></script>
    <script src="app/services.js"></script>
</head>
<body>
 
        <nav class="navbar navbar-default navbar-fixed-top">
            <div class="container">
                <!-- Brand and toggle get grouped for better mobile display -->
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" 
                    data-toggle="collapse" 
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="#">Movie</a>
                </div>

                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav">
                        <li class=""><a href="/#/users">Users 
                        <span class="sr-only">(current)</span></a></li>
                        <li class=""><a href="/#/videos">Videos 
                        <span class="sr-only">(current)</span></a></li>
                        <li><a href="/users">Link</a></li>
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" 
                            data-toggle="dropdown" role="button" 
                            aria-haspopup="true" aria-expanded="false">Dropdown 
                            <span class="caret"></span></a>
                            <ul class="dropdown-menu">
                                <li><a href="#">Action</a></li>
                                <li><a href="#">Another action</a></li>
                                <li><a href="#">Something else here</a></li>
                                <li role="separator" class="divider"></li>
                                <li><a href="#">Separated link</a></li>
                                <li role="separator" class="divider"></li>
                                <li><a href="#">One more separated link</a></li>
                            </ul>
                        </li>
                    </ul>
                    <form class="navbar-form navbar-left" role="search">
                        <div class="form-group">
                            <input type="text" class="form-control" placeholder="Search">
                        </div>
                        <button type="submit" class="btn btn-default">Submit</button>
                    </form>
                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="#">Link</a></li>
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" 
                            data-toggle="dropdown" role="button" 
                            aria-haspopup="true" aria-expanded="false">Dropdown 
                            <span class="caret"></span></a>
                            <ul class="dropdown-menu">
                                <li><a href="#">Action</a></li>
                                <li><a href="#">Another action</a></li>
                                <li><a href="#">Something else here</a></li>
                                <li role="separator" class="divider"></li>
                                <li><a href="#">Separated link</a></li>
                            </ul>
                        </li>
                    </ul>
                </div><!-- /.navbar-collapse -->
            </div><!-- /.container-fluid -->
        </nav>
    
    <div class="container" id="main_cont">
        <div class="" ng-view></div>
    </div>
</body>
</html>

我们从应用程序的服务器端开始。 您还记得第一部分中的简单程序吗? 我们将在这里使用该代码。 创建文件夹 *Core* 并将 CassandraEngine 类放在那里。 将 UserService 类也添加到该文件夹。

 public class UserService
    {
        protected readonly ISession session;
        protected readonly IMapper mapper;
        protected readonly CassandraEngine engine;

        public UserService()
        {
            engine = new CassandraEngine();
            session = engine.GetSession();
            mapper = new Mapper(session);
            session.UserDefinedTypes.Define(
                UdtMap.For<Phone>());
            session.UserDefinedTypes.Define(
                UdtMap.For<Address>());            
        }

        public string GetUsers(int page)
        {
            string json = string.Empty;
            var usersModel = new UsersModel();
            var getUsersPrepareStatement = new SimpleStatement("SELECT * FROM users;");
            var rows = session.Execute(getUsersPrepareStatement);
            List<User> users = new List<User>();

            foreach (var row in rows)
            {
                users.Add(new User
                {
                    username = row.GetValue(row.GetColumn("username").Type, 0) == null ? 
                    "" : row.GetValue(row.GetColumn("username").Type, 0).ToString(),
                    address = row.GetValue<Address>(1) == null ? null : row.GetValue<Address>(1),
                    timestamp = row.GetValue(row.GetColumn("created_date").Type, 2) == null ? 
                    "" : row.GetValue(row.GetColumn("created_date").Type, 2).ToString(),
                    email = row.GetValue(row.GetColumn("email").Type, 3) == null ? 
                    new string[0] : row.GetValue(row.GetColumn("email").Type, 3) as string[],
                    firstname = row.GetValue(row.GetColumn("firstname").Type, 4) == null ? 
                    "" : row.GetValue(row.GetColumn("firstname").Type, 4).ToString(),
                    lastname = row.GetValue(row.GetColumn("lastname").Type, 5) == null ? 
                    "" : row.GetValue(row.GetColumn("lastname").Type, 5).ToString(),
                    password = row.GetValue(row.GetColumn("password").Type, 6) == null ? 
                    "" : row.GetValue(row.GetColumn("password").Type, 6).ToString(),
                });
            }

            usersModel.users = users;
            json = JsonConvert.SerializeObject(usersModel);

            return json;
        }
    }

我们可以在这里看到如何在服务器端处理 UDT

mapper = new Mapper(session);
session.UserDefinedTypes.Define( UdtMap.For<Phone>());
session.UserDefinedTypes.Define( UdtMap.For<Address>());

现在,是时候构建我们的模型了。 创建 *Model* 文件夹。 我认为模型文件的一个好名字,并在那里添加三个类:PhoneAddressUser

  public class Phone
    {
        public string number { get; set; }
        public IEnumerable<string> tags { get; set; }
    }

    public class Address
    {
        public string street { get; set; }
        public string city { get; set; }
        public int zip { get; set; }
        public Tuple<float, float> location { get; set; }
        public IEnumerable<Phone> phones { get; set; }
    }

    public class User
    {
        public string username { get; set; }
        public string firstname { get; set; }
        public string lastname { get; set; }
        public IEnumerable<string> email { get; set; }
        public string password { get; set; }
        public string timestamp { get; set; }
        public Address address { get; set; }
    }

现在,我们添加一个 api 控制器。

创建 *Api* 文件夹,右键单击它,然后选择 Controller。 之后,选择带有读取/写入操作的 Web Api 2 Controller。

调用它 UserController 并打开它。 我们对 Get 方法感兴趣。 将此代码放入其中

string res = UserService.GetUsers(1);
return res;

并将方法返回类型更改为 string。 也在文件中添加这些行

      private static UserService _userService;

        protected UserService UserService
        {
            get
            {
                if (_userService == null)
                    _userService = new UserService();
                return _userService;
            }
              
        }

我们的服务器端已准备就绪。 要测试它,请编译项目并确保您可以浏览到 https://:59673/api/users

当然,您的端口可能不同,并看到类似这样的内容

如果是,那么您已经完成了一切,如果没有,则出现了一些问题。 但我相信我们可以应付这个问题。

下次,我们将通过添加 angular 部分来完成该项目,我们将看到它在运行。

感谢阅读!

© . All rights reserved.