Introduction
In the first part of the article, we installed DataStax DevCenter, created keyspace and column families, populated the database with some data and coded a simple application. Now, we will create user defined types and tuples and will get down to the brass tacks of our article - web application based Cassandra.
Background
If our application requires multiple tables, we can simplify our life by declaring user defined types (udf). UDF represents the related fields of information instead of storing the information in a separate table. We can define a group of properties as a type and access them separately or as a single entity. By mapping UDF to .NET type, we can deal with it like with .NET object after that in our application.
A tuple is a fixed-length set of typed positional fields without labels. Tuple is a key-value pair so we can think about tuple as if it were a Dictionary
object.
Using the Code
Now, we will create type phone that consists of number as text and tags as set of text. Set is like IEnumerable
in .NET.
Here is the sample of creating user defined type:
CREATE TYPE phone (
number text,
tags set<text>
);
Run it in DataStax DevCenter.
In its turn, we can use phone type as a part of another user defined type. Let's create address
type.
CREATE TYPE IF NOT EXISTS address (
street text,
city text,
zip int,
phones set<frozen<phone>>,
location frozen<tuple<float,float>>
);
Here, address
is UDT with simple properties as street
, city
, zip
as well as with set of UDT phones and tuple of two floats. Don't forget to change our column family to accept these types:
ALTER TABLE users ADD address frozen<address>;
We can see how DataStax proposes to insert data to table with user defined types in file 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)
}
);
Now, after our database is all set, let's come back to Visual Studio and write some code.
Create a new ASP.NET project and select empty templates and specify that you want folders and reference for MVC.
We will use angular in our project so we don't need MVC controllers and views. But we will need angular files and folders.
Create folder app in the project tree and add three JavaScript files there - app.js, controllers.js and services.js. Add index.html file to project root and open it. We'll need to add references to some styles and JavaScripts:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://ajax.googleapis.com/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.com/ajax/libs/angularjs/1.5.0-rc.2/angular-animate.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.1.2.js"></script>
as well as to our local styles and scripts:
<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>
Our project will be bootstrap based and HTML will look like this:
<!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.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/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.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://ajax.googleapis.com/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.com/ajax/libs/angularjs/1.5.0-rc.2/angular-animate.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/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">
<!--
<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>
<!--
<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><!--
</div><!--
</nav>
<div class="container" id="main_cont">
<div class="" ng-view></div>
</div>
</body>
</html>
We start from the server side of the application. Do you remember our simple program from Part I? We will use that code here. Create folder Core and place CassandraEngine
class there. Add UserService
class to that folder as well.
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;
}
}
We can see here how UDT is dealt on the server side:
mapper = new Mapper(session);
session.UserDefinedTypes.Define( UdtMap.For<Phone>());
session.UserDefinedTypes.Define( UdtMap.For<Address>());
It's time to build our model. Create Model folder. A good name for model files I think , and add three classes there: Phone
, Address
, User
.
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; }
}
Now, we add an api contoller.
Make Api folder, right click it and select Controller. After that, choose Web Api 2 Controller with read/write actions.
Call it UserController
and open it. We are interested in Get
method. Put in it this code:
string res = UserService.GetUsers(1);
return res;
and change method return type to string
. Add these rows in your file as well:
private static UserService _userService;
protected UserService UserService
{
get
{
if (_userService == null)
_userService = new UserService();
return _userService;
}
}
Our server side is ready. To test it, compile the project and make sure you can browse to http://localhost:59673/api/users
Of course, your port may be different, and see something like this:
If yes, you've done everything OK, if not something has gone wrong. But I'm sure we can cope with the problem.
Next time, we'll finish the project by adding angular part of it and we will see it in action.
Thank you for reading!