The document describes experiments measuring the performance of two algorithms for counting digits in numbers from 1 to a target number: a linear O(n) algorithm and a logarithmic O(log(n)) algorithm. Testing showed the linear algorithm had poor performance for large target numbers like 10^11, taking over 7 hours to run, while the logarithmic algorithm scaled well. A complete demo program was created to test number ranges from 10^0 to 10^19 and display average runtimes.
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Portfolio2
1. MAINLY CONSOLE APPS AND MVC ENTITY FRAMEWORK ASP
February 1, 2016
Authored by: Chris
Chris Worledge Portfolio 2
A SELECTION OF EXAMPLES OF MORE RECENT WORK
2. 1
ChrisWorledgePortfolio2|2/1/2016
Chris Worledge Portfolio 2
A selection of examples of more recent work
Page 2 Measuring the Performance of Algorithms (C#)
Page 36 Exploration of MongoDB using NodeJS
Page 40 Temporal Data Store (Efficient use of C# Data Structures;
Lists, Dictionaries etc.)
Page 53 Entity Framework with WebForms
Page 57 Entity Framework with MVC
Page 84 Web API with Angular JS
Page 97 Bank Cash Machine Programme and Database
3. 2
ChrisWorledgePortfolio2|2/1/2016
MEASURING THE PERFORMANCE OF ALGORITHMS
For comparison of different approaches to the same problem I have measured
the performance of two methods of measuring/calculating the digits within all
the numbers from one to any selected number. The problem was described to
me in terms of providing the numbers for doors where door numbers could
exceed 10^12! A less than likely scenario, but it indicated the leading zeros
would not be required.
The CountDigits method actually counts the digits within each number in turn
until the target number is reached. This is the brute force approach which is
ideal within small ranges, but does not scale up well.
The CalculateNumbers method actually adds the numbers of each digit as a
result of each digit in the target number.
A comparative unit test was employed to check they both produce the same
results:
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CountDigitsUnitTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
ulong index = 1, next = 1;
for (ulong value = 1; value < 10000000; value = next)
{
ulong[] linear = new CountDigits.DigitCount().CountDigits(value);
ulong[] log = new CountDigits.CountDigits().CalculateNumbers(value);
CollectionAssert.AreEqual(linear, log);
index++;
next = next + index;
}
}
}
}
This test couldn’t cover the complete range of the methods as the time required
to run such a check was prohibitive.
4. 3
ChrisWorledgePortfolio2|2/1/2016
Using 10^8 as a limit took 6 minutes over a whole day!
In Big O notation the first approach has O(n), a linear relationship which can
be ideal with very small number ranges, but has terrible performance with
large numbers, whilst the second has O(log(n)), which is much more scalable to
requirements in modern business environments.
We need System and System.Diagnostics (for the stopwatch class to measure
the execution times).
using System;
using System.Diagnostics;
namespace HotelApplication
{
class Program
{
public static void Main(string[] args)
{
5. 4
ChrisWorledgePortfolio2|2/1/2016
ulong max = 10000000000 ;
//the upper number n in the range 1 to n
var timeTest = Stopwatch.StartNew();//set a stopwatch going
ulong[] digValues = new CountDigits().CalculateNumbers(max);
timeTest.Stop();//call the method, and stop the stopwatch
var elapsedValue = timeTest.Elapsed;
string longStringTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", elapsedValue.Hours,
elapsedValue.Minutes, elapsedValue.Seconds, elapsedValue.Milliseconds);//display the time
and the values
Console.WriteLine("Input: " + max.ToString());
Console.WriteLine("");
Console.WriteLine("Time in milliseconds = " + elapsedValue.TotalMilliseconds.ToString() +
" milliseconds");
Console.WriteLine("");
Console.WriteLine("Time = " + longStringTime);
Console.WriteLine("");
Console.WriteLine("0: " + digValues[0].ToString());
Console.WriteLine("1: " + digValues[1].ToString());
Console.WriteLine("2: " + digValues[2].ToString());
Console.WriteLine("3: " + digValues[3].ToString());
Console.WriteLine("4: " + digValues[4].ToString());
Console.WriteLine("5: " + digValues[5].ToString());
Console.WriteLine("6: " + digValues[6].ToString());
Console.WriteLine("7: " + digValues[7].ToString());
Console.WriteLine("8: " + digValues[8].ToString());
Console.WriteLine("9: " + digValues[9].ToString());
Console.WriteLine("");
//Do the same things again for the other method
var clock = Stopwatch.StartNew();
ulong[] digCount = new DigitCount().CountDigits(max);
clock.Stop();
var elapsedMillis = clock.ElapsedMilliseconds;
var timeelapsed = clock.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", timeelapsed.Hours,
timeelapsed.Minutes, timeelapsed.Seconds, timeelapsed.Milliseconds);
Console.WriteLine("Input: " + max.ToString());
Console.WriteLine("");
Console.WriteLine("Time in milliseconds = " + timeelapsed.TotalMilliseconds.ToString() +
" milliseconds");
Console.WriteLine("");
Console.WriteLine("Time = " + elapsedTime);
Console.WriteLine("");
Console.WriteLine("0: " + digCount[0].ToString());
Console.WriteLine("1: " + digCount[1].ToString());
Console.WriteLine("2: " + digCount[2].ToString());
Console.WriteLine("3: " + digCount[3].ToString());
Console.WriteLine("4: " + digCount[4].ToString());
Console.WriteLine("5: " + digCount[5].ToString());
Console.WriteLine("6: " + digCount[6].ToString());
Console.WriteLine("7: " + digCount[7].ToString());
Console.WriteLine("8: " + digCount[8].ToString());
Console.WriteLine("9: " + digCount[9].ToString());
Console.WriteLine("");
6. 5
ChrisWorledgePortfolio2|2/1/2016
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}
}
The anticipated outcome would be a linear time to logarithmic input for the
CalculateNumbers method; whilst the CountDigits method would remain linear
against input and become inpractical for large numbers.
The console display for 10^9:
8. 7
ChrisWorledgePortfolio2|2/1/2016
The console display of 10^11:
An averaging technique was employed to reduce the impact of overhead, and
display the true trend of the underlying algorithm. This was only practical for
the Olog(n) algorithm due to the much increased run times of the O(n)
algorithm. This will have introduced error, but it’s impact would be small.
9. 8
ChrisWorledgePortfolio2|2/1/2016
A table of results shows the performance of each algorithm in ms.
Input Input(scientific) Olog(n) O(n)
1 1.E+00 0.0005 0.3589
10 1.E+01 0.00052 0.0049
100 1.E+02 0.000748 0.0158
1000 1.E+03 0.00984 0.1433
10000 1.E+04 0.001136 1.272
100000 1.E+05 0.001343 18.056
1000000 1.E+06 0.001694 176.6585
10000000 1.E+07 0.001851 1820.4105
100000000 1.E+08 0.002001 19687.2353
1000000000 1.E+09 0.0022248 218771.4353
10000000000 1.E+10 0.002532 2427029.663
100000000000 1.E+11 0.002837 25599515.25
1000000000000 1E+12 0.003152
10000000000000 1E+13 0.003309
100000000000000 1E+14 0.003699
1000000000000000 1E+15 0.004099
10000000000000000 1E+16 0.004624
100000000000000000 1E+17 0.005271
1000000000000000000 1E+18 0.006046
10000000000000000000 1E+19 0.007024
18446744073709551615 1.84467E+19 0.0383061
The O(n) results stop at 10^11 as that took seven and a half hours, so it would
be reasonable to expect 10^12 to take around three days.
A linear comparison of both algorithms, demonstrates the limits of practical
use of the brute force approach.
10. 9
ChrisWorledgePortfolio2|2/1/2016
If the mid point input value of 5 million were related to population, the linear
algorithm would demonstrate poor performance with most town and city
populations, but not cope at all with larger cities or counties, let alone
countries.
Independent charting against a logarithmic input shows the performance
comparison more fully.
0
5000000
10000000
15000000
20000000
25000000
30000000
O(n)
12. 11
ChrisWorledgePortfolio2|2/1/2016
A complete demo was devised which allowed any number ranges outputs to be
recorded in a text file, and a display of the results of successive powers of ten
finishing with 2^64 – 1.
using System;
using System.Diagnostics;
using System.IO;
namespace CleanDigitCounter
{
class Program
{
static void Main(string[] args)
{
consDemo();//runs a demo using the range of values from 10^0 to 10^19 and
2^64-1
}
private static void consDemo()
{
double[] times = new double[22] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int index = 0;
ulong max = 1;
while (index <= 19)
{
double totalMiliseconds = 0;
for (int i = 1; i <= 10; i++)
{
var avTest = Stopwatch.StartNew();
ulong[] alues = new CountDigits().CalculateNumbers(max);
avTest.Stop();
totalMiliseconds += avTest.Elapsed.TotalMilliseconds;
}
Console.WriteLine("");
Console.WriteLine("Input: " + max.ToString());
var avElapsedValue = totalMiliseconds / 10;
times[index] += avElapsedValue;
string avElapsed = avElapsedValue.ToString();
Console.WriteLine("Average Milliseconds for Value " + avElapsed);
Console.WriteLine("");
if (max == 1)
{
double totalMilis = 0;
for (int i = 1; i <= 10; i++)
{
var avTest = Stopwatch.StartNew();
ulong[] alues = new CountDigits().CalculateNumbers(max);
avTest.Stop();
totalMilis += avTest.Elapsed.TotalMilliseconds;
}
Console.WriteLine("");
13. 12
ChrisWorledgePortfolio2|2/1/2016
Console.WriteLine("Input: " + max.ToString());
var avValue = totalMilis / 10;
times[index] += avValue;
string av = avValue.ToString();
Console.WriteLine("Average Milliseconds for Value " + av);
Console.WriteLine("");
}
var timeTest = Stopwatch.StartNew();
ulong[] digValues = new CountDigits().CalculateNumbers(max);
timeTest.Stop();
var elapsedValue = timeTest.Elapsed;
string longStringTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
elapsedValue.Hours, elapsedValue.Minutes, elapsedValue.Seconds,
elapsedValue.Milliseconds);
Console.WriteLine("Input: " + max.ToString());
Console.WriteLine("");
Console.WriteLine("Time in milliseconds = " +
elapsedValue.TotalMilliseconds.ToString() + " milliseconds");
Console.WriteLine("");
Console.WriteLine("Time = " + longStringTime);
Console.WriteLine("");
Console.WriteLine("0: " + digValues[0].ToString());
Console.WriteLine("1: " + digValues[1].ToString());
Console.WriteLine("2: " + digValues[2].ToString());
Console.WriteLine("3: " + digValues[3].ToString());
Console.WriteLine("4: " + digValues[4].ToString());
Console.WriteLine("5: " + digValues[5].ToString());
Console.WriteLine("6: " + digValues[6].ToString());
Console.WriteLine("7: " + digValues[7].ToString());
Console.WriteLine("8: " + digValues[8].ToString());
Console.WriteLine("9: " + digValues[9].ToString());
Console.WriteLine("");
if (index < 9)//just so the demo doesn't take weeks to run
{
var clock = Stopwatch.StartNew();
ulong[] digCount = new DigitCount().CountDigits(max);
clock.Stop();
var elapsedMillis = clock.ElapsedMilliseconds;
var timeelapsed = clock.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
timeelapsed.Hours, timeelapsed.Minutes, timeelapsed.Seconds, timeelapsed.Milliseconds);
Console.WriteLine("Input: " + max.ToString());
Console.WriteLine("");
Console.WriteLine("Time in milliseconds = " +
timeelapsed.TotalMilliseconds.ToString() + " milliseconds");
Console.WriteLine("");
Console.WriteLine("Time = " + elapsedTime);
28. 27
ChrisWorledgePortfolio2|2/1/2016
Input: 1000000000
Average Milliseconds for Value 0.00197
Input: 1000000000
Time in milliseconds = 0.0023 milliseconds
Time = 00:00:00.00
0: 788888898
1: 900000001
2: 900000000
3: 900000000
4: 900000000
5: 900000000
6: 900000000
7: 900000000
8: 900000000
9: 900000000
Input: 10000000000
Average Milliseconds for Value 0.00253
Input: 10000000000
Time in milliseconds = 0.0026 milliseconds
Time = 00:00:00.00
0: 8888888899
1: 10000000001
2: 10000000000
3: 10000000000
4: 10000000000
5: 10000000000
29. 28
ChrisWorledgePortfolio2|2/1/2016
6: 10000000000
7: 10000000000
8: 10000000000
9: 10000000000
Input: 100000000000
Average Milliseconds for Value 0.00269
Input: 100000000000
Time in milliseconds = 0.0032 milliseconds
Time = 00:00:00.00
0: 98888888900
1: 110000000001
2: 110000000000
3: 110000000000
4: 110000000000
5: 110000000000
6: 110000000000
7: 110000000000
8: 110000000000
9: 110000000000
Input: 1000000000000
Average Milliseconds for Value 0.00296
Input: 1000000000000
Time in milliseconds = 0.0035 milliseconds
Time = 00:00:00.00
0: 1088888888901
1: 1200000000001
30. 29
ChrisWorledgePortfolio2|2/1/2016
2: 1200000000000
3: 1200000000000
4: 1200000000000
5: 1200000000000
6: 1200000000000
7: 1200000000000
8: 1200000000000
9: 1200000000000
Input: 10000000000000
Average Milliseconds for Value 0.00475
Input: 10000000000000
Time in milliseconds = 0.0035 milliseconds
Time = 00:00:00.00
0: 11888888888902
1: 13000000000001
2: 13000000000000
3: 13000000000000
4: 13000000000000
5: 13000000000000
6: 13000000000000
7: 13000000000000
8: 13000000000000
9: 13000000000000
Input: 100000000000000
Average Milliseconds for Value 0.00391
31. 30
ChrisWorledgePortfolio2|2/1/2016
Input: 100000000000000
Time in milliseconds = 0.0046 milliseconds
Time = 00:00:00.00
0: 128888888888903
1: 140000000000001
2: 140000000000000
3: 140000000000000
4: 140000000000000
5: 140000000000000
6: 140000000000000
7: 140000000000000
8: 140000000000000
9: 140000000000000
Input: 1000000000000000
Average Milliseconds for Value 0.00469
Input: 1000000000000000
Time in milliseconds = 0.0041 milliseconds
Time = 00:00:00.00
0: 1388888888888904
1: 1500000000000001
2: 1500000000000000
3: 1500000000000000
4: 1500000000000000
5: 1500000000000000
6: 1500000000000000
7: 1500000000000000
32. 31
ChrisWorledgePortfolio2|2/1/2016
8: 1500000000000000
9: 1500000000000000
Input: 10000000000000000
Average Milliseconds for Value 0.00479
Input: 10000000000000000
Time in milliseconds = 0.0055 milliseconds
Time = 00:00:00.00
0: 14888888888888905
1: 16000000000000001
2: 16000000000000000
3: 16000000000000000
4: 16000000000000000
5: 16000000000000000
6: 16000000000000000
7: 16000000000000000
8: 16000000000000000
9: 16000000000000000
Input: 100000000000000000
Average Milliseconds for Value 0.00457
Input: 100000000000000000
Time in milliseconds = 0.0046 milliseconds
Time = 00:00:00.00
0: 158888888888888906
1: 170000000000000001
2: 170000000000000000
33. 32
ChrisWorledgePortfolio2|2/1/2016
3: 170000000000000000
4: 170000000000000000
5: 170000000000000000
6: 170000000000000000
7: 170000000000000000
8: 170000000000000000
9: 170000000000000000
Input: 1000000000000000000
Average Milliseconds for Value 0.0049
Input: 1000000000000000000
Time in milliseconds = 0.0052 milliseconds
Time = 00:00:00.00
0: 1688888888888888907
1: 1800000000000000001
2: 1800000000000000000
3: 1800000000000000000
4: 1800000000000000000
5: 1800000000000000000
6: 1800000000000000000
7: 1800000000000000000
8: 1800000000000000000
9: 1800000000000000000
Input: 10000000000000000000
Average Milliseconds for Value 0.0055
Input: 10000000000000000000
34. 33
ChrisWorledgePortfolio2|2/1/2016
Time in milliseconds = 0.0061 milliseconds
Time = 00:00:00.00
0: 17888888888888888908
1: 553255926290448385
2: 553255926290448384
3: 553255926290448384
4: 553255926290448384
5: 553255926290448384
6: 553255926290448384
7: 553255926290448384
8: 553255926290448384
9: 553255926290448384
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Input: 18446744073709551615
Average Milliseconds for Value 1 : 0.0044365
Average Milliseconds for Value 10 : 8.3E-05
35. 34
ChrisWorledgePortfolio2|2/1/2016
Average Milliseconds for Value 100 : 0.0002
Average Milliseconds for Value 1,000 : 0.000142
Average Milliseconds for Value 10,000 : 0.000167
Average Milliseconds for Value 100,000 : 0.000193
Average Milliseconds for Value 1,000,000 : 0.000286
Average Milliseconds for Value 10,000,000 : 0.000262
Average Milliseconds for Value 100,000,000 : 0.000182
Average Milliseconds for Value 1000,000,000 : 0.000197
Average Milliseconds for Value 10,000,000,000 : 0.000253
Average Milliseconds for Value 100,000,000,000 : 0.000269
Average Milliseconds for Value 1,000,000,000,000 : 0.000296
Average Milliseconds for Value 10,000,000,000,000 : 0.000475
Average Milliseconds for Value 100,000,000,000,000 : 0.000391
Average Milliseconds for Value 1,000,000,000,000,000 : 0.000469
36. 35
ChrisWorledgePortfolio2|2/1/2016
Average Milliseconds for Value 10,000,000,000,000,000 : 0.000479
Average Milliseconds for Value 100,000,000,000,000,000 : 0.000457
Average Milliseconds for Value 1,000,000,000,000,000,000 : 0.00049
Average Milliseconds for Value 10,000,000,000,000,000,000 : 0.00055
Average Milliseconds for Value 18446744073709551615 : 0.0029604
Press enter to close...
37. 36
ChrisWorledgePortfolio2|2/1/2016
EXPLORATION OF MONGODB USING NODEJS
This was achieved following a Microsoft Tutorial
Links the app to the database instance, we can then pass the database
instance to the MongoDB Client and populate and interrogate it as follows:
41. 40
ChrisWorledgePortfolio2|2/1/2016
C# TEMPORAL DATA STORE
You will be implementing a read-biased in-memory temporal data store.
A temporal store allows point-in-time queries about data. An example would be
the price of an exchange traded security. We might capture the price of the
security once an hour throughout the trading day, and store the price in a
temporal store. We can then query the temporal store to determine at any given
time, what the most recent captured price was.
This example illustrates the following key terms, which will be used throughout
this document:
1. Identifier - a key (e.g. the security id), for which we want to store a
history of observations
2. History - the list of observations for a given identifier
3. Observation - a piece of data which is associated with a particular
identifier at a particular timestamp
4. Timestamp - a given point in time
The latest observation for an identifier at a timestamp is found by searching in
the identifier's history for the first observation whose timestamp is less than, or
equal to, the sought timestamp.
For the purposes of this scenario, you should assume the following:
1. Identifiers are integers in the inclusive range [0..2^31 - 1]
2. Timestamps are integers in the inclusive range [0..2^63 - 1]
3. Data is represented as a contiguous string of non-whitespace
characters. For example, "jiggawatt" is a valid piece of data. The string "great
scot" is not, owing to its whitespace.
4. Users may interact with the temporal store, as well as processes. you
should be strict in what data you accept, but should provide suitable error
messages where the user has erred.
5. Capacity; there is no requirement to restrict your store to a given size,
but you may assume that you will be provided with no more than 10,000
identifiers, each with no more than 1,000 history entries, and no data item will
be no more than 16 characters.
42. 41
ChrisWorledgePortfolio2|2/1/2016
Your temporal data store will communicate with other processes via standard
input and output. A series of commands are read and applied to the data store
from standard input. The results of evaluating the commands should be
written to standard output. A command will only ever be one line; the result of
executing a command will be a single output line, except for the QUIT
command.
When there are no more lines to consume, your temporal data store should
exit. There is no need to persist data in the store between executions (this is an
in-memory temporal store).
class Program
{
static void Main(string[] args)
{
/*Holds the references to all the history stores, so we can find the required
history if it exists*/
List<DataDict> contain = new List<DataDict>();
//We make a few histories (from 0 - 4) and populate them with dummy data
for (int i = 0; i < 5; i++)
{
string j = "100";
string k = "1.1";
string dummy = "FirstCreate " + i + " " + j + " " + k;
new CommandHandler(dummy, contain);
}
for (int i = 0; i < 5; i++)
{
var p = 110;
var q = 1.2;
for (int l = 0; l < 10; l++)
{
string dummy = "FirstUpdate " + i.ToString() + " " + p.ToString() + "
" + q.ToString();
new CommandHandler(dummy, contain);
p = p + 10;
q = q + 0.1;
}
}
//Cue the console up, ready to receive user input
string line;
line = Console.ReadLine();
if (line != null)
{
new CommandHandler(line, contain);
}
}
}
43. 42
ChrisWorledgePortfolio2|2/1/2016
The commands which can be executed against your data store are described
below. Note that:
- Items in <angle brackets> represent required arguments, but the angle
brackets themselves do not form part of the command
- Items in [square brackets] are optional arguments
- Successfully processed commands should always start their response with
"OK ", followed by the result of executing the command
- Commands which could not be executed should always start their response
with "ERR ", followed by a reasonable error message.
- Commands are not sensitive to whitespace; arguments must be separated by
at least one character of whitespace, but may be separated by more.
CREATE <id> <timestamp> <data>
- Creates a new history for the given identifier, if there is no existing
history. Adds an observation to the newly created history for the given
timestamp and data. CREATE should not be executed if the provided identifier
already has a history. Returns the data which was inserted, to confirm
insertion.
UPDATE <id> <timestamp> <data>
- Inserts an observation for the given identifier, timestamp and data.
Returns the data from the prior observation for that timestamp.
DELETE <id> [timestamp]
- If timestamp is provided, deletes all observations for the given identifier
from that timestamp forward. Returns the current observation at the given
timestamp, or an error if there is no available observation.
- If timestamp is not provided, deletes the history for the given identifier,
and returns the observation with the greatest timestamp from the history
which has been deleted.
44. 43
ChrisWorledgePortfolio2|2/1/2016
GET <id> <timestamp>
- Returns the data from the observation for the given identifier at the given
timestamp, or an error if there is no available observation.
LATEST <id>
- Locates the observation with the greatest timestamp from the history for
the given identifier, and responds with its timestamp and data.
QUIT - Terminates the process immediately. No response should be written.
We use a List to store references to a series of Dictionaries, one for
each security.
class CommandHandler
{
string id = string.Empty;
string timeStamp = string.Empty;
string data = string.Empty;
string Command = string.Empty;
int ID;
long dateTime;
string line;
public CommandHandler(string command, List<DataDict> contain)
{
//separate out the different elements of the user input
char[] seperator = new char[] { ' ' };
string[] commands = command.Split(seperator,
StringSplitOptions.RemoveEmptyEntries);
Command = commands[0].Trim().ToLower();
if (commands.Count() > 1)
{
id = commands[1].Trim();
}
if (commands.Count() > 2)
{
timeStamp = commands[2].Trim();
}
if (commands.Count() > 3)
{
data = commands[3].Trim();
}
switch (Command)
{
case "create":
Create(contain);
45. 44
ChrisWorledgePortfolio2|2/1/2016
break;
case "update":
Update(contain);
break;
case "delete":
Delete(contain);
break;
case "get":
Get(contain);
break;
case "latest":
Latest(contain);
break;
//These two are just to provide some intial values, so little comms with
user
case "firstcreate":
FirstCreate(contain);
break;
case "firstupdate":
FirstUpdate(contain);
break;
case "quit":
Environment.Exit(0);
break;
default:
Console.WriteLine("I am sorry, I do not understand that command.");
line = Console.ReadLine();
if (line != null)
{
new CommandHandler(line, contain);
}
break;
}
}
protected void Create(List<DataDict> contain)
{
if (int.TryParse(id, out ID))
{
int index = contain.FindIndex(e => e.Name == ID);
if (index >= 0)
{
Console.WriteLine("Error: The history already exists for ID '" + ID +
"'");
46. 45
ChrisWorledgePortfolio2|2/1/2016
}
else
{
DataDict n = new DataDict(ID);
contain.Add(n);//adds the reference to the history store in the
container list
if (long.TryParse(timeStamp, out dateTime))
{
n.Add(dateTime, data);
Console.WriteLine("OK " + data.ToString());
}
else
{
Console.WriteLine("Error: The DateTime value provided is invalid.
Please ensure you provide a valid DateTime value.");
}
}
}
line = Console.ReadLine();
if (line != null)
{
new CommandHandler(line, contain);
}
}
protected void Update(List<DataDict> contain)
{
if (int.TryParse(id, out ID))
{
int index = -1;
index = contain.FindIndex(e => e.Name == ID);
if (index >= 0)
{
var n = (from DataList in contain
where DataList.Name == ID
select DataList).FirstOrDefault();
if (long.TryParse(timeStamp, out dateTime))
{
int exists = -1;
exists = n.DoesExist(dateTime);
string previous = string.Empty;
if (exists > 0)
{
previous = n.Update(dateTime, data);
}
else
{
previous = n.Add(dateTime, data);
}
Console.WriteLine("OK " + previous);
}
else
{
Console.WriteLine("Error: The DateTime value provided is invalid.
Please ensure you provide a valid DateTime value.");
}
47. 46
ChrisWorledgePortfolio2|2/1/2016
}
else
{
Console.WriteLine("Error: No history exists for identifier '" +
ID.ToString() + "' ");
}
}
else
{
Console.WriteLine("Error: The ID provided is invalid. Please ensure it is
a number.");
}
line = Console.ReadLine();
if (line != null)
{
new CommandHandler(line, contain);
}
}
protected void Delete(List<DataDict> contain)
{
if (int.TryParse(id, out ID))
{
int index = contain.FindIndex(e => e.Name == ID);
if (index >= 0)
{
var n = (from DataList in contain
where DataList.Name == ID
select DataList).FirstOrDefault();
if (long.TryParse(timeStamp, out dateTime))
{
KeyValuePair<long, string> got = n.Specific(dateTime);
n.deleteAfter(dateTime);
Console.WriteLine("OK " + got.Value.ToString());
}
//if there is no timestamp, remove the whole list
else
{
string newestValue = n.Latest().Value;
contain.Remove(n);
Console.WriteLine("OK " + newestValue);
}
}
else
{
Console.WriteLine("Error: The ID provided [" + ID.ToString() + "] has
no history. Please ensure you provide a valid ID.");
}
}
else
{
Console.WriteLine("Error: The ID provided is Invalid. Please ensure it is
a number.");
}
line = Console.ReadLine();
if (line != null)
48. 47
ChrisWorledgePortfolio2|2/1/2016
{
new CommandHandler(line, contain);
}
}
protected void Get(List<DataDict> contain)
{
if (int.TryParse(id, out ID))
{
int index = contain.FindIndex(e => e.Name == ID);
if (index >= 0)
{
var n = (from DataList in contain
where DataList.Name == ID
select DataList).FirstOrDefault();
if (long.TryParse(timeStamp, out dateTime))
{
if (n.ExistsOrLess(dateTime) > 0)
{
KeyValuePair<long, string> got = n.Specific(dateTime);
Console.WriteLine("OK " + got.Value.ToString());
}
else
{
Console.WriteLine("Error: The ID provided [" + ID.ToString()
+ "] has no history prior to the supplied DateTime value.");
}
}
else
{
Console.WriteLine("Error: The DateTime value provided is invalid.
Please ensure you provide a valid DateTime value.");
}
}
else
{
Console.WriteLine("Error: The ID provided [" + ID.ToString() + "] has
no history. Please ensure you provide a valid ID.");
}
}
else
{
Console.WriteLine("Error: The ID provided is Invalid. Please ensure it is
a number.");
}
line = Console.ReadLine();
if (line != null)
{
new CommandHandler(line, contain);
}
}
protected void Latest(List<DataDict> contain)
{
if (int.TryParse(id, out ID))
{
49. 48
ChrisWorledgePortfolio2|2/1/2016
int index = contain.FindIndex(e => e.Name == ID);
if (index >= 0)
{
var n = (from DataList in contain
where DataList.Name == ID
select DataList).FirstOrDefault();
KeyValuePair<long, string> latest = n.Latest();
Console.WriteLine("OK " + latest.Key.ToString() + " " +
latest.Value.ToString());
}
else
{
Console.WriteLine("Error: No history exists for identifier '" +
ID.ToString() + "' ") ;
}
}
else
{
Console.WriteLine("Error: The ID provided is Invalid. Please ensure it is
a number.");
}
line = Console.ReadLine();
if (line != null)
{
new CommandHandler(line, contain);
}
}
protected void FirstCreate(List<DataDict> contain)
{
if (int.TryParse(id, out ID))
{
int index = contain.FindIndex(e => e.Name == ID);
if (index >= 0)
{
Console.WriteLine("Error: The id value " + ID.ToString() + " already
exists");
}
else
{
DataDict n = new DataDict(ID);
contain.Add(n);//adds the reference to the history store in the
container list
if (long.TryParse(timeStamp, out dateTime))
{
DataItem d = new DataItem(data, dateTime);
n.Add(dateTime, data);//the first record in the history
Console.WriteLine("OK " + data.ToString());
}
}
}
}
protected void FirstUpdate(List<DataDict> contain)
{
if (int.TryParse(id, out ID))
50. 49
ChrisWorledgePortfolio2|2/1/2016
{
var n = (from DataList in contain
where DataList.Name == ID
select DataList).FirstOrDefault();
if (long.TryParse(timeStamp, out dateTime))
{
n.Add(dateTime, data);//additional records in the history
Console.WriteLine("OK " + data.ToString());
}
}
}
}
class DataDict
{
int name;
/*the Property only has an accessor to prevent accidental edit.
It allows multiple records to be stored and retrieved against the same ID
This structure allows you to access just the information relating to the ID
(Security) submitted
The alternative of putting all records in one list would mean selecting the
required ID from
the dictionary into a working dictionary each time, or working within the clutter
of many irrelevant records */
public int Name { get { return name; } }
public SortedDictionary<long, string> dataDict { get; set; }
public DataDict(int n)
{
name = n;
dataDict = new SortedDictionary<long, string>();
}
public string Add(long timePassed, string data)
{
string prev = string.Empty;
long prevKey = -1;
if (dataDict.Keys.Count > 0)
{
prevKey = dataDict.Keys.Max();
}
if (prevKey >= 0)
{
var previous = dataDict.Where(x => x.Key == prevKey).First();
prev = previous.Value;
}
else { prev = "not available"; }
dataDict.Add(timePassed, data);
return prev;
}
public int DoesExist(long dateTime)
51. 50
ChrisWorledgePortfolio2|2/1/2016
{
if (dataDict.ContainsKey(dateTime))
{
return 1;
}
else
{
return 0;
}
}
public string Update(long timePassed, string data)
{
string prev = string.Empty;
var previous = dataDict.FirstOrDefault(e => e.Key == timePassed);
prev = previous.Value;
dataDict.Remove(timePassed);
dataDict.Add(timePassed, data);
return prev;
}
public string getBiggestData()
{
return dataDict.Values.Max().ToString();
}
public int ExistsOrLess(long dateTime)
{
var allUnder = dataDict.Where(e => e.Key <= dateTime);
if (allUnder.Count() > 0)
{
return 1;
}
else
{
return 0;
}
}
public KeyValuePair<long, string> Specific(long dateTime)
{
if (dataDict.ContainsKey(dateTime))
{
return dataDict.FirstOrDefault(e => e.Key == dateTime);
}
else
{
var allUnder = dataDict.Where(e => e.Key < dateTime);
return allUnder.Last();
}
}
52. 51
ChrisWorledgePortfolio2|2/1/2016
public void deleteBefore(long dateTime)
{
SortedDictionary<long, string> tempDict = new SortedDictionary<long,
string>(dataDict.Where(e => e.Key >= dateTime).ToDictionary(e => e.Key, e => e.Value));
dataDict = tempDict;
}
public void deleteAfter(long dateTime)
{
SortedDictionary<long, string> tempDict = new SortedDictionary<long,
string>(dataDict.Where(e => e.Key <= dateTime).ToDictionary(e => e.Key, e => e.Value));
dataDict = tempDict;
}
public KeyValuePair<long, string> Latest()
{
long highest = dataDict.Keys.Max();
return dataDict.Where(x => x.Key == highest).First();
}
}
54. 53
ChrisWorledgePortfolio2|2/1/2016
ENTITY FRAMEWORK WITH WEBFORMS
An example of displaying the relationships between different staff from a
database using entity framework and web forms:
Data
ID ForeName SurName Manager
0 Lucy Atwell NULL
1 Carla Barns 0
2 Tara Crane 0
3 Freda Dunbarr 0
4 Patricia Edwards 1
5 Vicky Fox 1
6 Margaret Grant 2
7 Cindy Hall 2
8 Kirsty Irwin 3
10 Jane James 3
ID EmpID JobID
1 0 1
2 1 2
3 2 4
4 3 6
5 4 3
6 5 5
7 6 7
8 7 3
9 8 5
10 9 7
11 10 7
55. 54
ChrisWorledgePortfolio2|2/1/2016
ID Job
1 Pharmacist
2 Physiotherapist
3 Cardiac Technician
4 Radiographer
5 Phlebotomist
6 Biomedical Scientist
7 Pharmacy Technician
Data Access Classes
public partial class Ldemo : DataContext
{
public Table<Emp> Emp;
public Table<EmpJob> EmpJob;
public Table<Job> Job;
public Ldemo(string connection) : base(connection) { }
}
public class Relationship
{
public String Forename { get; set; }
public String Surname { get; set; }
public String Job { get; set; }
public String Manager { get; set; }
public Relationship(String f, String s, String j, String m) {
Forename = f;
Surname = s;
Job = j;
Manager = m;
}
}
Form Code Behind
public partial class Page1 : System.Web.UI.Page
{
public List<Relationship> relations = new List<Relationship>();
protected void Page_Load(object sender, EventArgs e)
{
var conString =
System.Configuration.ConfigurationManager.ConnectionStrings["LinqDemoConnectionString"].T
oString();
Ldemo db = new Ldemo(conString);
relations = (from a in db.Emp
join b in db.Emp on new { Manager =
a.Manager.GetValueOrDefault(-1) } equals new { Manager = b.ID } into b_join
56. 55
ChrisWorledgePortfolio2|2/1/2016
from b in b_join.DefaultIfEmpty()
join EmpJobs in db.EmpJob on new { ID = a.ID } equals new { ID =
EmpJobs.EmpID }
join Jobs in db.Job on new { JobID = EmpJobs.JobID } equals new
{ JobID = Jobs.ID }
select new Relationship(
a.ForeName,
a.SurName,
Jobs.Job1,
b.ForeName + " " + b.SurName
)).ToList();
}
}
The code creates a list called relations which holds all of the staff names with
their job and their manager. Since Lucy Atwell’s manager field contains null,
her manager field should be blank. All the other staff have a number
representing another member of staff is their manager.
Form aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Page1.aspx.cs"
Inherits="LinqDemo.Page1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr>
<td><b>Forename</b></td>
<td><b>Surname</b></td>
<td><b>Job</b></td>
<td><b>Manager</b></td>
</tr>
<% foreach (var relation in relations) { %>
<tr><td><%= relation.Forename %></td>
<td><%= relation.Surname %></td>
<td><%= relation.Job %></td>
<td><%= relation.Manager %></td></tr>
<% } %>
</table>
</div>
</form>
</body>
</html>
58. 57
ChrisWorledgePortfolio2|2/1/2016
ENTITY FRAMEWORK WITH MVC
This application demonstrates the use of entity framework 6 with an MVC5
asp.net (C#) 4.5 combination:
The purpose of the application is to store, retrieve, and display information
about shares.
It has different markets; shares; and share prices, so displays tables of these
allowing Create; Read; Update; and Delete functionality. It also allows display of
tables sorted by different parameters, and a view of just the most recent prices
for each share. The prices and shares table’s pages have a chart facility which
provides a line chart of the selected share price over time.
This is the Home page from the navigation bar along the top.
The subsequent shots follow along the navigation bar (List of stocks; List of
markets; List of prices; Sorted list of prices; Latest prices).
63. 62
ChrisWorledgePortfolio2|2/1/2016
From the Stocks page the charts link click for Browns gives:
Adding a new price:
The current date and time is inserted for you, and you select the stock from the
drop-down.
64. 63
ChrisWorledgePortfolio2|2/1/2016
Models:
namespace MVC5ef6.Models
{
using System;
using System.Collections.Generic;
public partial class Stock
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage",
"CA2214:DoNotCallOverridableMethodsInConstructors")]
public Stock()
{
this.Prices = new HashSet<Price>();
}
public int stockID { get; set; }
public string stockName { get; set; }
public Nullable<int> marketID { get; set; }
public virtual Market Market { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage",
"CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Price> Prices { get; set; }
}
public partial class Market
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage",
"CA2214:DoNotCallOverridableMethodsInConstructors")]
public Market()
{
this.Stocks = new HashSet<Stock>();
}
public int marketID { get; set; }
public string marketName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage",
"CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Stock> Stocks { get; set; }
}
public partial class Price
{
public int ID { get; set; }
public Nullable<int> stockID { get; set; }
public Nullable<System.DateTime> Stamp { get; set; }
public Nullable<decimal> Pence { get; set; }
public virtual Stock Stock { get; set; }
}
public partial class LatestPrice
{
65. 64
ChrisWorledgePortfolio2|2/1/2016
public long ID { get; set; }
public string stockName { get; set; }
public string marketName { get; set; }
public Nullable<System.DateTime> Stamp { get; set; }
public Nullable<decimal> Pence { get; set; }
}
public partial class PriceListItem
{
public int ID { get; set; }
public Nullable<int> stockID { get; set; }
public Nullable<System.DateTime> Stamp { get; set; }
public Nullable<decimal> Pence { get; set; }
public string stockName { get; set; }
}
public class StockPriceModel
{
public int ID { get; set; }
public string ChartTitle { get; set; }
public string StampTitle { get; set; }
public string PenceTitle { get; set; }
public int stockID { get; set; }
public StockPrice PriceData { get; set; }
}
public class StockPrice
{
public int ID { get; set; }
public string Stamp { get; set; }
public decimal Pence { get; set; }
}
}
Views:
Shared: _Layout;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - My ASP.NET Application</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript"
src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
72. 71
ChrisWorledgePortfolio2|2/1/2016
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
public class LatestPricesController : Controller
{
private MVC5demoEntities db = new MVC5demoEntities();
// GET: LatestPrices
public ActionResult Index()
{
return View(db.LatestPrices.OrderBy(l => l.marketName).ToList());
}
// GET: LatestPrices/Details/5
public ActionResult Details(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
LatestPrice latestPrice = db.LatestPrices.Find(id);
if (latestPrice == null)
{
return HttpNotFound();
}
return View(latestPrice);
}
// GET: LatestPrices/Create
public ActionResult Create()
{
return View();
}
// POST: LatestPrices/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include =
"ID,stockName,marketName,Pence,Stamp")] LatestPrice latestPrice)
{
if (ModelState.IsValid)
{
db.LatestPrices.Add(latestPrice);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(latestPrice);
73. 72
ChrisWorledgePortfolio2|2/1/2016
}
// GET: LatestPrices/Edit/5
public ActionResult Edit(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
LatestPrice latestPrice = db.LatestPrices.Find(id);
if (latestPrice == null)
{
return HttpNotFound();
}
return View(latestPrice);
}
// POST: LatestPrices/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,stockName,marketName,Pence,Stamp")]
LatestPrice latestPrice)
{
if (ModelState.IsValid)
{
db.Entry(latestPrice).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(latestPrice);
}
// GET: LatestPrices/Delete/5
public ActionResult Delete(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
LatestPrice latestPrice = db.LatestPrices.Find(id);
if (latestPrice == null)
{
return HttpNotFound();
}
return View(latestPrice);
}
// POST: LatestPrices/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(long id)
{
LatestPrice latestPrice = db.LatestPrices.Find(id);
db.LatestPrices.Remove(latestPrice);
db.SaveChanges();
return RedirectToAction("Index");
}
74. 73
ChrisWorledgePortfolio2|2/1/2016
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
public class MarketsController : Controller
{
private MVC5demoEntities db = new MVC5demoEntities();
// GET: Markets
public ActionResult Index()
{
return View(db.Markets.ToList());
}
// GET: Markets/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Market market = db.Markets.Find(id);
if (market == null)
{
return HttpNotFound();
}
return View(market);
}
// GET: Markets/Create
public ActionResult Create()
{
return View();
}
// POST: Markets/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "marketID,marketName")] Market market)
{
if (ModelState.IsValid)
{
db.Markets.Add(market);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(market);
}
75. 74
ChrisWorledgePortfolio2|2/1/2016
// GET: Markets/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Market market = db.Markets.Find(id);
if (market == null)
{
return HttpNotFound();
}
return View(market);
}
// POST: Markets/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "marketID,marketName")] Market market)
{
if (ModelState.IsValid)
{
db.Entry(market).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(market);
}
// GET: Markets/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Market market = db.Markets.Find(id);
if (market == null)
{
return HttpNotFound();
}
return View(market);
}
// POST: Markets/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Market market = db.Markets.Find(id);
db.Markets.Remove(market);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
76. 75
ChrisWorledgePortfolio2|2/1/2016
{
db.Dispose();
}
base.Dispose(disposing);
}
}
public class NamedPrice
{
Models.Stock name { get; set; }
Models.Price price { get; set; }
}
public class PriceListItemsController : Controller
{
private MVC5demoEntities db = new MVC5demoEntities();
// GET: PriceListItems
public ActionResult Index()
{
var pricesForList = db.Prices.Join(db.Stocks, a => a.stockID, b => b.stockID,
(a, b) => new { a, b }).
Select(c => new PriceListItem { ID = c.a.ID, stockID = c.a.stockID, Stamp
= c.a.Stamp, Pence = c.a.Pence, stockName = c.b.stockName }).
OrderBy(q => q.Stamp).GroupBy(s => s.stockName);
IQueryable<IGrouping<string, PriceListItem>> ListedPrices =
pricesForList;/*We want to controll the display order,
but we don't need the grouping order as a seperate data attribute so we will
take the items into a list*/
List <PriceListItem> DisplayList = new List<PriceListItem>();
foreach (IGrouping<string, PriceListItem> item in ListedPrices)
{
foreach (PriceListItem listItem in item)
{
DisplayList.Add(listItem);
}
}
//now we can pass the list for display
return View(DisplayList);
}
// GET: PriceListItems/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
PriceListItem priceListItem = db.PriceListItems.Find(id);
if (priceListItem == null)
{
return HttpNotFound();
}
77. 76
ChrisWorledgePortfolio2|2/1/2016
return View(priceListItem);
}
// GET: PriceListItems/Create
public ActionResult Create()
{
return View();
}
// POST: PriceListItems/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,stockID,Stamp,Pence,stockName")]
PriceListItem priceListItem)
{
if (ModelState.IsValid)
{
db.PriceListItems.Add(priceListItem);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(priceListItem);
}
// GET: PriceListItems/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
PriceListItem priceListItem = db.PriceListItems.Find(id);
if (priceListItem == null)
{
return HttpNotFound();
}
return View(priceListItem);
}
// POST: PriceListItems/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,stockID,Stamp,Pence,stockName")]
PriceListItem priceListItem)
{
if (ModelState.IsValid)
{
db.Entry(priceListItem).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(priceListItem);
}
// GET: PriceListItems/Delete/5
public ActionResult Delete(int? id)
{
78. 77
ChrisWorledgePortfolio2|2/1/2016
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
PriceListItem priceListItem = db.PriceListItems.Find(id);
if (priceListItem == null)
{
return HttpNotFound();
}
return View(priceListItem);
}
// POST: PriceListItems/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
PriceListItem priceListItem = db.PriceListItems.Find(id);
db.PriceListItems.Remove(priceListItem);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
public class PricesController : Controller
{
private MVC5demoEntities db = new MVC5demoEntities();
// GET: Prices
public ActionResult Index()
{
var prices = db.Prices.Include(p => p.Stock);
return View(prices.ToList());
}
// GET: Prices/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Price price = db.Prices.Find(id);
if (price == null)
{
return HttpNotFound();
79. 78
ChrisWorledgePortfolio2|2/1/2016
}
return View(price);
}
// GET: Prices/Create
public ActionResult Create()
{
ViewBag.stockID = new SelectList(db.Stocks, "stockID", "stockName");
return View();
}
// POST: Prices/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,stockID,Stamp,Pence")] Price
price)
{
if (ModelState.IsValid)
{
db.Prices.Add(price);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.stockID = new SelectList(db.Stocks, "stockID", "stockName",
price.stockID);
return View(price);
}
// GET: Prices/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Price price = db.Prices.Find(id);
if (price == null)
{
return HttpNotFound();
}
ViewBag.stockID = new SelectList(db.Stocks, "stockID", "stockName",
price.stockID);
return View(price);
}
// POST: Prices/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,stockID,Stamp,Pence")] Price price)
{
if (ModelState.IsValid)
{
db.Entry(price).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
80. 79
ChrisWorledgePortfolio2|2/1/2016
ViewBag.stockID = new SelectList(db.Stocks, "stockID", "stockName",
price.stockID);
return View(price);
}
// POST: Prices/Chart/5
public ActionResult Chart(int? id)
{
if (id != null)
{
int stock;
int.TryParse(id.ToString(), out stock);//drag the int out of the ?int
string stockName = db.Stocks.Where(a => a.stockID == stock).Select(a =>
a.stockName).FirstOrDefault() ;
StockPriceModel SPModel = new StockPriceModel();
SPModel.ChartTitle = stockName;
SPModel.StampTitle = "DateTime";
SPModel.PenceTitle = "Pence";
SPModel.stockID = stock;
return View(SPModel);
}
else
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
}
public JsonResult GetChart(int stock)
{
var ChartData = db.Prices.Where(a => a.stockID.HasValue ? a.stockID == stock
: false)
.Select(p => new { Stamp = p.Stamp.HasValue ? p.Stamp.Value :
DateTime.Now, p.Pence }).
OrderBy(q => q.Stamp);//all the dates and prices in date order
List<StockPrice> CleanChartData = new List<StockPrice>();
CultureInfo culture = new CultureInfo("pt-BR");//so we get day before month!
int x = 0;
foreach (var t in ChartData)
{
string time = t.Stamp.ToString("G", culture);//give a date to display in
javascript
decimal price;
decimal.TryParse(t.Pence.ToString(), out price);//because t.pence is a
nullable decimal
StockPrice current = new StockPrice();
current.ID = x;
current.Stamp = time;
current.Pence = price;
CleanChartData.Add(current);
x++;
}
return Json(CleanChartData, JsonRequestBehavior.AllowGet);
81. 80
ChrisWorledgePortfolio2|2/1/2016
}
// GET: Prices/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Price price = db.Prices.Find(id);
if (price == null)
{
return HttpNotFound();
}
return View(price);
}
// POST: Prices/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Price price = db.Prices.Find(id);
db.Prices.Remove(price);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
public class StocksController : Controller
{
private MVC5demoEntities db = new MVC5demoEntities();
// GET: Stocks
public ActionResult Index()
{
var stocks = db.Stocks.Include(s => s.Market);
return View(stocks.ToList());
}
// GET: Stocks/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
82. 81
ChrisWorledgePortfolio2|2/1/2016
}
Stock stock = db.Stocks.Find(id);
if (stock == null)
{
return HttpNotFound();
}
return View(stock);
}
// GET: Stocks/Create
public ActionResult Create()
{
ViewBag.marketID = new SelectList(db.Markets, "marketID", "marketName");
return View();
}
// POST: Stocks/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "stockID,stockName,marketID")] Stock
stock)
{
if (ModelState.IsValid)
{
db.Stocks.Add(stock);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.marketID = new SelectList(db.Markets, "marketID", "marketName",
stock.marketID);
return View(stock);
}
// GET: Stocks/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Stock stock = db.Stocks.Find(id);
if (stock == null)
{
return HttpNotFound();
}
ViewBag.marketID = new SelectList(db.Markets, "marketID", "marketName",
stock.marketID);
return View(stock);
}
// POST: Stocks/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "stockID,stockName,marketID")] Stock
stock)
{
83. 82
ChrisWorledgePortfolio2|2/1/2016
if (ModelState.IsValid)
{
db.Entry(stock).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.marketID = new SelectList(db.Markets, "marketID", "marketName",
stock.marketID);
return View(stock);
}
// POST: Stocks/Chart/5
public ActionResult Chart(int? id)
{
if (id != null)
{
int stock;
int.TryParse(id.ToString(), out stock);//drag the int out of the ?int
string stockName = db.Stocks.Where(a => a.stockID == stock).Select(a =>
a.stockName).FirstOrDefault();
StockPriceModel SPModel = new StockPriceModel();
SPModel.ChartTitle = stockName;
SPModel.StampTitle = "DateTime";
SPModel.PenceTitle = "Pence";
SPModel.stockID = stock;
return View(SPModel);
}
else
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
}
public JsonResult GetChart(int stock)
{
var ChartData = db.Prices.Where(a => a.stockID.HasValue ? a.stockID == stock
: false)
.Select(p => new { Stamp = p.Stamp.HasValue ? p.Stamp.Value :
DateTime.Now, p.Pence }).
OrderBy(q => q.Stamp);//all the dates and prices in date order
List<StockPrice> CleanChartData = new List<StockPrice>();
CultureInfo culture = new CultureInfo("pt-BR");//so we get day before month!
int x = 0;
foreach (var t in ChartData)
{
string time = t.Stamp.ToString("d", culture);//give a date to display in
javascript
decimal price;
decimal.TryParse(t.Pence.ToString(), out price);//because t.pence is a
nullable decimal
StockPrice current = new StockPrice();
current.ID = x;
current.Stamp = time;
current.Pence = price;
CleanChartData.Add(current);
98. 97
ChrisWorledgePortfolio2|2/1/2016
AT HOME TASK
There is a special cash machine, without any security, that dispenses money
(notes and coins). The machine has a given initial state of what coins and notes
it has available.
The initial state is: 100x1p, 100x2p, 100x5p, 100x10p, 100x20p, 100x50p,
100x£1, 100x£2, 50x£5, 50x£10, 50x£20, 50x£50.
You should create a program that is given the value to withdraw as an input.
Program the cash machine, so it has 2 algorithms that can be swapped
(swapping can be done by rebuilding and rerunning the application):
1. Algorithm that returns least number of items (coins or notes)
2. Algorithm that returns the highest number of £20 notes possible
Output the number of coins and notes given for each withdrawal.
The machine should output the count and value of coins and notes dispensed
and the balance amount left.
The program should be extendible and written using .NET framework. Use the
best approach you can to implement the solution.
Examples
Algorithm 1
Input (Withdrawal amount)
120.00
Output
£50x2, £20x1
£X.XX balance
Algorithm 2
Input
120.00
Output
£20x6
£X.XX balance
100. 99
ChrisWorledgePortfolio2|2/1/2016
Second Algorithm with £20 note bias:
Program:
namespace CashMachine
{
class Program
{
static void Main(string[] args)
{
Bank thisBank = new Bank();
thisBank.Algorithm = true;//allows the maximum twenties algorithm
while (true)
{
Console.WriteLine("Please enter required amount:");
string line = Console.ReadLine();
if (line != null)
{
Decimal debit;
if (Decimal.TryParse(line, out debit))
{
string response = thisBank.debit(debit);
Console.WriteLine(response);
}
101. 100
ChrisWorledgePortfolio2|2/1/2016
else
{
Console.WriteLine("You have entered an invalid amount.");
}
}
}
}
}
}
Bank:
namespace CashMachine
{
class Bank
{
private Money[] Monies { get; set; }
public Boolean Algorithm { get; set; }
public Bank()
{
Monies = new Money[] {
new Money("£50", 50, 50 ),
new Money("£20", 20, 50 ),
new Money("£10", 10, 50 ),
new Money("£5", 5, 50 ),
new Money("£2", 2, 100 ),
new Money("£1", 1, 100 ),
new Money("50p", .5m, 100 ),//the appended m forces the Decimal type
new Money("20p", .2m, 100 ),
new Money("10p", .1m, 100 ),
new Money("5p", .05m, 100 ),
new Money("2p", .02m, 100 ),
new Money("1p", .01m, 100 )
};
Algorithm = false;//default to all denominations
}
public String debit(Decimal amount)
{
StringBuilder message = new StringBuilder();
Decimal debitvalue = amount;
if (amount <= getBalance())//check the money is available
{
debitAlgorithm(debitvalue, message);//takes the money by denomination
depending on the algorithm
message.Append("rnBalance remaining is £");
string balance = getBalance().ToString("#.##");
message.Append(balance);
return message.ToString();//tell them which notes and coins are being
supplied and how much is left in the machine.
}
else//we can't afford to service this request
102. 101
ChrisWorledgePortfolio2|2/1/2016
{
return "The machine does not have sufficient funds to grant your
requestrn We are sorry for the inconvenience.";
}
}
private Decimal getBalance()
{
Decimal balance = 0;
foreach (Money money in Monies)
{
var value = money.value * money.quantity;
balance += value;
}
return balance;
}
private void debitAlgorithm(Decimal debitvalue, StringBuilder message)
{
int numberOfDenominations = Monies.Length;
int index = 0;//set the start point at fifties
Decimal requiredMoney = debitvalue;
Boolean messageAdded = false;
if (Algorithm)
{
index = 1;
requiredMoney = fullAlgorithm(index, messageAdded, requiredMoney,
message);//do the twenties first if set to that Algorithm
index = 0;
requiredMoney = fullAlgorithm(index, messageAdded, requiredMoney,
message);//do the fifties in case there weren't enough twenties left
index = 2;//carry on through the loop from £10 down
}
for (int i = index; i < numberOfDenominations; i++)
{
requiredMoney = fullAlgorithm(i, messageAdded, requiredMoney,
message);//we update the required amount each time
}
}
private Decimal fullAlgorithm(int i, Boolean messageAdded, Decimal debitvalue,
StringBuilder message)
{
Decimal requiredMoney = debitvalue;
int number = (int)(requiredMoney / Monies[i].value);//just the whole number
of this denomination
if (number > 0 && number < Monies[i].quantity)//We want some and that many
are available
{
requiredMoney = requiredMoney % Monies[i].value;//the leftover after the
above
Monies[i].quantity -= number;//debit the machine total for this
denomination