From 4bac8e934647a40319856a6cde2f42f56837514b Mon Sep 17 00:00:00 2001 From: Sebastian Pfliegel Date: Tue, 5 Dec 2017 16:29:35 +0100 Subject: [PATCH 1/2] Add SLES C# tutorials --- samples/tutorials/c#/SLES/README.md | 77 ++++++++++++ .../SqlServerColumnstoreSample/Program.cs | 110 ++++++++++++++++++ .../SqlServerColumnstoreSample.csproj | 21 ++++ .../SLES/SqlServerEFSample/EFSampleContext.cs | 20 ++++ .../c#/SLES/SqlServerEFSample/Program.cs | 101 ++++++++++++++++ .../SqlServerEFSample.csproj | 13 +++ .../c#/SLES/SqlServerEFSample/Task.cs | 18 +++ .../c#/SLES/SqlServerEFSample/User.cs | 22 ++++ .../c#/SLES/SqlServerSample/Program.cs | 37 ++++++ .../SqlServerSample/SqlServerSample.csproj | 12 ++ 10 files changed, 431 insertions(+) create mode 100644 samples/tutorials/c#/SLES/README.md create mode 100644 samples/tutorials/c#/SLES/SqlServerColumnstoreSample/Program.cs create mode 100644 samples/tutorials/c#/SLES/SqlServerColumnstoreSample/SqlServerColumnstoreSample.csproj create mode 100644 samples/tutorials/c#/SLES/SqlServerEFSample/EFSampleContext.cs create mode 100644 samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs create mode 100644 samples/tutorials/c#/SLES/SqlServerEFSample/SqlServerEFSample.csproj create mode 100644 samples/tutorials/c#/SLES/SqlServerEFSample/Task.cs create mode 100644 samples/tutorials/c#/SLES/SqlServerEFSample/User.cs create mode 100644 samples/tutorials/c#/SLES/SqlServerSample/Program.cs create mode 100644 samples/tutorials/c#/SLES/SqlServerSample/SqlServerSample.csproj diff --git a/samples/tutorials/c#/SLES/README.md b/samples/tutorials/c#/SLES/README.md new file mode 100644 index 00000000..397898c6 --- /dev/null +++ b/samples/tutorials/c#/SLES/README.md @@ -0,0 +1,77 @@ +# Get started with SQL Server and C# on SLES + +Get started quickly with developing applications in C# on SLES with SQL Server + + +### Contents + +[About this sample](#about-this-sample)
+[Before you begin](#before-you-begin)
+[Run this sample](#run-this-sample)
+[Sample details](#sample-details)
+[Disclaimers](#disclaimers)
+[Related links](#related-links)
+ + + + +## About this sample + +- **Applies to:** SQL Server 2016 (or higher) +- **Workload:** + - CRUD with .NET Core + - CRUD with Entity Framework Core + - Performance improvements with Columnstore +- **Programming Language:** C# +- **Authors:** ajlam + + + +## Before you begin + +To run this sample, you need the following prerequisites. + +**Software prerequisites:** + +1. SQL Server 2016 (or higher) +2. .NET Core 2.0 +3. Entity Framework Core 2.0 +4. A text editor + +## Run this sample + +1. Select the specific tutorial you want to run through. + +2. From your favorite text editor, open the Program.cs file corresponding to the tutorial you wish to run through. Update the connection string username and password with your own. + +3. From your terminal, change directories to the tutorial folder (ex. SqlServerSample) you're running through. Restore the .NET Core dependencies by performing the following command: + + ``` + dotnet restore + ``` + +4. Run the program by performing the following command: + + ``` + dotnet run + ``` + +5. Repeat the above steps for any of the other tutorials provided. + + + +## Sample details + +Please visit the [C# on SLES tutorial](https://www.microsoft.com/en-us/sql-server/developer-get-started/csharp/sles/) to run through the sample in full with more detail. + + + +## Disclaimers +The scripts and this guide are provided as samples. They are not part of any Azure service and are not covered by any SLA or other Azure-related agreements. They are provided as-is with no warranties express or implied. Microsoft takes no responsibility for the use of the scripts or the accuracy of this document. Familiarize yourself with the scripts before using them. + + + +## Related Links + +For more information, see these articles: +* To see more getting started tutorials, visit our [tutorials page](https://www.microsoft.com/en-us/sql-server/developer-get-started/) \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerColumnstoreSample/Program.cs b/samples/tutorials/c#/SLES/SqlServerColumnstoreSample/Program.cs new file mode 100644 index 00000000..d0029b80 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerColumnstoreSample/Program.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SqlServerColumnstoreSample +{ + class Program + { + static void Main(string[] args) + { + try + { + Console.WriteLine("*** SQL Server Columnstore demo ***"); + + // Build connection string + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder.DataSource = "localhost"; // update me + builder.UserID = "sa"; // update me + builder.Password = "your_password"; // update me + builder.InitialCatalog = "master"; + + // Connect to SQL + Console.Write("Connecting to SQL Server ... "); + using (SqlConnection connection = new SqlConnection(builder.ConnectionString)) + { + connection.Open(); + Console.WriteLine("Done."); + + // Create a sample database + Console.Write("Dropping and creating database 'SampleDB' ... "); + String sql = "DROP DATABASE IF EXISTS [SampleDB]; CREATE DATABASE [SampleDB]"; + using (SqlCommand command = new SqlCommand(sql, connection)) + { + command.ExecuteNonQuery(); + Console.WriteLine("Done."); + } + + // Insert 5 million rows into the table 'Table_with_5M_rows' + Console.Write("Inserting 5 million rows into table 'Table_with_5M_rows'. This takes ~1 minute, please wait ... "); + StringBuilder sb = new StringBuilder(); + sb.Append("USE SampleDB; "); + sb.Append("WITH a AS (SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS a(a))"); + sb.Append("SELECT TOP(5000000)"); + sb.Append("ROW_NUMBER() OVER (ORDER BY a.a) AS OrderItemId "); + sb.Append(",a.a + b.a + c.a + d.a + e.a + f.a + g.a + h.a AS OrderId "); + sb.Append(",a.a * 10 AS Price "); + sb.Append(",CONCAT(a.a, N' ', b.a, N' ', c.a, N' ', d.a, N' ', e.a, N' ', f.a, N' ', g.a, N' ', h.a) AS ProductName "); + sb.Append("INTO Table_with_5M_rows "); + sb.Append("FROM a, a AS b, a AS c, a AS d, a AS e, a AS f, a AS g, a AS h;"); + sql = sb.ToString(); + using (SqlCommand command = new SqlCommand(sql, connection)) + { + command.ExecuteNonQuery(); + Console.WriteLine("Done."); + } + + // Execute SQL query without columnstore index + double elapsedTimeWithoutIndex = SumPrice(connection); + Console.WriteLine("Query time WITHOUT columnstore index: " + elapsedTimeWithoutIndex + "ms"); + + // Add a Columnstore Index + Console.Write("Adding a columnstore to table 'Table_with_5M_rows' ... "); + sql = "CREATE CLUSTERED COLUMNSTORE INDEX columnstoreindex ON Table_with_5M_rows;"; + using (SqlCommand command = new SqlCommand(sql, connection)) + { + command.ExecuteNonQuery(); + Console.WriteLine("Done."); + } + + // Execute the same SQL query again after columnstore index was added + double elapsedTimeWithIndex = SumPrice(connection); + Console.WriteLine("Query time WITH columnstore index: " + elapsedTimeWithIndex + "ms"); + + // Calculate performance gain from adding columnstore index + Console.WriteLine("Performance improvement with columnstore index: " + + Math.Round(elapsedTimeWithoutIndex / elapsedTimeWithIndex) + "x!"); + } + Console.WriteLine("All done. Press any key to finish..."); + Console.ReadKey(true); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + } + + public static double SumPrice(SqlConnection connection) + { + String sql = "SELECT SUM(Price) FROM Table_with_5M_rows"; + long startTicks = DateTime.Now.Ticks; + using (SqlCommand command = new SqlCommand(sql, connection)) + { + try + { + var sum = command.ExecuteScalar(); + TimeSpan elapsed = TimeSpan.FromTicks(DateTime.Now.Ticks) - TimeSpan.FromTicks(startTicks); + return elapsed.TotalMilliseconds; + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + } + return 0; + } + } +} \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerColumnstoreSample/SqlServerColumnstoreSample.csproj b/samples/tutorials/c#/SLES/SqlServerColumnstoreSample/SqlServerColumnstoreSample.csproj new file mode 100644 index 00000000..0ba4d376 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerColumnstoreSample/SqlServerColumnstoreSample.csproj @@ -0,0 +1,21 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "debugType": "portable", + "emitEntryPoint": true + }, + "dependencies": { + "System.Data.SqlClient": "4.1.0" + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "imports": "dnxcore50" + } + } +} \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerEFSample/EFSampleContext.cs b/samples/tutorials/c#/SLES/SqlServerEFSample/EFSampleContext.cs new file mode 100644 index 00000000..42eb5a17 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerEFSample/EFSampleContext.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; + +namespace SqlServerEFSample +{ + public class EFSampleContext : DbContext + { + string _connectionString; + public EFSampleContext(string connectionString) + { + this._connectionString = connectionString; + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseSqlServer(this._connectionString); + } + + public DbSet Users { get; set; } + public DbSet Tasks { get; set; } + } +} \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs b/samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs new file mode 100644 index 00000000..4a0ec441 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs @@ -0,0 +1,101 @@ +using System; +using System.Linq; +using System.Data.SqlClient; +using System.Collections.Generic; + +namespace SqlServerEFSample +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("** C# CRUD sample with Entity Framework Core and SQL Server **\n"); + try + { + // Build connection string + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder.DataSource = "localhost"; // update me + builder.UserID = "sa"; // update me + builder.Password = "your_password"; // update me + builder.InitialCatalog = "EFSampleDB"; + + using (EFSampleContext context = new EFSampleContext(builder.ConnectionString)) + { + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + Console.WriteLine("Created database schema from C# classes."); + + // Create demo: Create a User instance and save it to the database + User newUser = new User { FirstName = "Anna", LastName = "Shrestinian" }; + context.Users.Add(newUser); + context.SaveChanges(); + Console.WriteLine("\nCreated User: " + newUser.ToString()); + + // Create demo: Create a Task instance and save it to the database + Task newTask = new Task() { Title = "Ship Helsinki", IsComplete = false, DueDate = DateTime.Parse("04-01-2017") }; + context.Tasks.Add(newTask); + context.SaveChanges(); + Console.WriteLine("\nCreated Task: " + newTask.ToString()); + + // Association demo: Assign task to user + newTask.AssignedTo = newUser; + context.SaveChanges(); + Console.WriteLine("\nAssigned Task: '" + newTask.Title + "' to user '" + newUser.GetFullName() + "'"); + + // Read demo: find incomplete tasks assigned to user 'Anna' + Console.WriteLine("\nIncomplete tasks assigned to 'Anna':"); + var query = from t in context.Tasks + where t.IsComplete == false && + t.AssignedTo.FirstName.Equals("Anna") + select t; + foreach(var t in query) + { + Console.WriteLine(t.ToString()); + } + + // Update demo: change the 'dueDate' of a task + Task taskToUpdate = context.Tasks.First(); // get the first task + Console.WriteLine("\nUpdating task: " + taskToUpdate.ToString()); + taskToUpdate.DueDate = DateTime.Parse("06-30-2016"); + context.SaveChanges(); + Console.WriteLine("dueDate changed: " + taskToUpdate.ToString()); + + // Delete demo: delete all tasks with a dueDate in 2016 + Console.WriteLine("\nDeleting all tasks with a dueDate in 2016"); + DateTime dueDate2016 = DateTime.Parse("12-31-2016"); + query = from t in context.Tasks + where t.DueDate < dueDate2016 + select t; + foreach(Task t in query) + { + Console.WriteLine("Deleting task: " + t.ToString()); + context.Tasks.Remove(t); + } + context.SaveChanges(); + + // Show tasks after the 'Delete' operation - there should be 0 tasks + Console.WriteLine("\nTasks after delete:"); + List tasksAfterDelete = (from t in context.Tasks select t).ToList(); + if (tasksAfterDelete.Count == 0) + { + Console.WriteLine("[None]"); + } + else + { + foreach (Task t in query) + { + Console.WriteLine(t.ToString()); + } + } + } + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + + Console.WriteLine("All done. Press any key to finish..."); + Console.ReadKey(true); + } + } +} \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerEFSample/SqlServerEFSample.csproj b/samples/tutorials/c#/SLES/SqlServerEFSample/SqlServerEFSample.csproj new file mode 100644 index 00000000..ded8aa8f --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerEFSample/SqlServerEFSample.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp2.0 + + + + + + + + \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerEFSample/Task.cs b/samples/tutorials/c#/SLES/SqlServerEFSample/Task.cs new file mode 100644 index 00000000..83031f20 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerEFSample/Task.cs @@ -0,0 +1,18 @@ +using System; + +namespace SqlServerEFSample +{ + public class Task + { + public int TaskId { get; set; } + public string Title { get; set; } + public DateTime DueDate { get; set; } + public bool IsComplete { get; set; } + public virtual User AssignedTo { get; set; } + + public override string ToString() + { + return "Task [id=" + this.TaskId + ", title=" + this.Title + ", dueDate=" + this.DueDate.ToString() + ", IsComplete=" + this.IsComplete + "]"; + } + } +} \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerEFSample/User.cs b/samples/tutorials/c#/SLES/SqlServerEFSample/User.cs new file mode 100644 index 00000000..cbeb8fc8 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerEFSample/User.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace SqlServerEFSample +{ + public class User + { + public int UserId { get; set; } + public String FirstName { get; set; } + public String LastName { get; set; } + public virtual IList Tasks { get; set; } + + public String GetFullName() + { + return this.FirstName + " " + this.LastName; + } + public override string ToString() + { + return "User [id=" + this.UserId + ", name=" + this.GetFullName() + "]"; + } + } +} \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerSample/Program.cs b/samples/tutorials/c#/SLES/SqlServerSample/Program.cs new file mode 100644 index 00000000..3b7591b0 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerSample/Program.cs @@ -0,0 +1,37 @@ +using System; +using System.Text; +using System.Data.SqlClient; + +namespace SqlServerSample +{ + class Program + { + static void Main(string[] args) + { + try + { + // Build connection string + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder.DataSource = "localhost"; // update me + builder.UserID = "sa"; // update me + builder.Password = "your_password"; // update me + builder.InitialCatalog = "master"; + + // Connect to SQL + Console.Write("Connecting to SQL Server ... "); + using (SqlConnection connection = new SqlConnection(builder.ConnectionString)) + { + connection.Open(); + Console.WriteLine("Done."); + } + } + catch (SqlException e) + { + Console.WriteLine(e.ToString()); + } + + Console.WriteLine("All done. Press any key to finish..."); + Console.ReadKey(true); + } + } +} \ No newline at end of file diff --git a/samples/tutorials/c#/SLES/SqlServerSample/SqlServerSample.csproj b/samples/tutorials/c#/SLES/SqlServerSample/SqlServerSample.csproj new file mode 100644 index 00000000..f2e9ab20 --- /dev/null +++ b/samples/tutorials/c#/SLES/SqlServerSample/SqlServerSample.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp2.0 + + + + + + + \ No newline at end of file From ac26197aae1a0daa1baa2e61dc4a2e5b0cc284ee Mon Sep 17 00:00:00 2001 From: Sebastian Pfliegel Date: Tue, 5 Dec 2017 16:30:51 +0100 Subject: [PATCH 2/2] Fix date parsing --- samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs b/samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs index 4a0ec441..2e3423c1 100644 --- a/samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs +++ b/samples/tutorials/c#/SLES/SqlServerEFSample/Program.cs @@ -32,7 +32,7 @@ namespace SqlServerEFSample Console.WriteLine("\nCreated User: " + newUser.ToString()); // Create demo: Create a Task instance and save it to the database - Task newTask = new Task() { Title = "Ship Helsinki", IsComplete = false, DueDate = DateTime.Parse("04-01-2017") }; + Task newTask = new Task() { Title = "Ship Helsinki", IsComplete = false, DueDate = DateTime.ParseExact("04-01-2017", "MM-dd-yyyy", CultureInfo.InvariantCulture) }; context.Tasks.Add(newTask); context.SaveChanges(); Console.WriteLine("\nCreated Task: " + newTask.ToString()); @@ -56,13 +56,13 @@ namespace SqlServerEFSample // Update demo: change the 'dueDate' of a task Task taskToUpdate = context.Tasks.First(); // get the first task Console.WriteLine("\nUpdating task: " + taskToUpdate.ToString()); - taskToUpdate.DueDate = DateTime.Parse("06-30-2016"); + taskToUpdate.DueDate = DateTime.ParseExact("06-30-2016", "MM-dd-yyyy", CultureInfo.InvariantCulture); context.SaveChanges(); Console.WriteLine("dueDate changed: " + taskToUpdate.ToString()); // Delete demo: delete all tasks with a dueDate in 2016 Console.WriteLine("\nDeleting all tasks with a dueDate in 2016"); - DateTime dueDate2016 = DateTime.Parse("12-31-2016"); + DateTime dueDate2016 = DateTime.ParseExact("12-31-2016", "MM-dd-yyyy", CultureInfo.InvariantCulture); query = from t in context.Tasks where t.DueDate < dueDate2016 select t;