This sample contains example data in .csv format, together with methods that transform it into in-memory collections of Customers, Products, Orders, and Order Details. To further experiment with PLINQ, you can paste code examples from certain other topics into the code in this topic and invoke it from the Main method. You can also use this data with your own PLINQ queries.
The data represents a subset of the Northwind database. Fifty (50) customer records are included, but not all fields. A subset of the rows from the Orders and corresponding Order_Detail data for every Customer is included. All Products are included.
To set up this sample
Create a Visual Basic or Visual C# console application project.
Replace the contents of Module1.vb or Program.cs by using the code that follows these steps.
On the Project menu, click Add New Item. Select Text File and then click OK. Copy the data in this topic and then paste it in the new text file. On the File menu, click Save, name the file Plinqdata.csv, and then save it in the folder that contains your source code files.
Press F5 to verify that the project builds and runs correctly. The following output should be displayed in the console window.
Customer count: 50 Product count: 77 Order count: 190 Order Details count: 483 Press any key to exit.
sample · csharpsamples/snippets/csharp/VS_Snippets_Misc/plinq/cs/plinqsamples.cs50
namespace PLINQ_Samples
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
class City
{
public int Population = 0;
public string Name = string.Empty;
}
class Person
{
public string Mayor = string.Empty;
public string CityName = string.Empty;
}
partial class PLINQProgram
{
static int Compute(int i) { return 1; }
static void Main_2(string[] args)
{
// SimpleQuery();
// OrderedQuery3();
//SequentialDemo(); ;
Console.ReadLine();
}
static void DOP()
{
var source = Enumerable.Range(0, 100000);
//<snippet5>
var query = from item in source.AsParallel().WithDegreeOfParallelism(2)
where Compute(item) > 42
select item;
//</snippet5>
}
static void Test()
{
var cities = new List<City>();
var people = new List<Person>();
// Order Preservation In PLINQ 1st snippet
//<snippet8>
var cityQuery =
(from city in cities.AsParallel()
where city.Population > 10000
select city).Take(1000);
//</snippet8>
// Order Preservation In PLINQ 2nd snippet
//<snippet9>
var orderedCities =
(from city in cities.AsParallel().AsOrdered()
where city.Population > 10000
select city).Take(1000);
//</snippet9>
//<snippet6>
var orderedCities2 =
(from city in cities.AsParallel().AsOrdered()
where city.Population > 10000
select city).Take(1000);
var finalResult =
from city in orderedCities2.AsUnordered()
join p in people.AsParallel()
on city.Name equals p.CityName into details
from c in details
select new
{
city.Name,
Pop = city.Population,
c.Mayor
};
foreach (var city in finalResult) { /*...*/ }
//</snippet6>
//...
////…
//You can write the same query in method based syntax as follows:
//[example]
//Another way to minimize the expense of order preservation is to impose a new ordering explicitly at a later stage in the query, after all filters have been applied, as shown in the following example:
//<snippet7>
var orderedCities3 =
(from city in cities.AsParallel()
where city.Population > 10000
orderby city.Name
select city).Take(1000);
//</snippet7>
}
static void SimpleQuery()
{
var source = Enumerable.Range(100, 20000);
// Result sequence might be out of order.
var parallelQuery =
from num in source.AsParallel()
where num % 10 == 0
select num;
// Process result sequence in parallel
parallelQuery.ForAll(DoSomething);
// Or use foreach to merge results first.
foreach (var n in parallelQuery)
{
Console.WriteLine(n);
}
// You can also use ToArray, ToList, etc
// as with LINQ to Objects.
var parallelQuery2 =
(from num in source.AsParallel()
where num % 10 == 0
select num).ToArray();
// Method syntax is also supported
var parallelQuery3 =
source.AsParallel()
.Where(n => n % 10 == 0)
.Select(n => n);
Console.ReadLine();
}
static void DoSomething(int i) { }
static void OrderedQuery()
{
//<snippet12>
var source = Enumerable.Range(9, 10000);
// Source is ordered; let's preserve it.
var parallelQuery =
from num in source.AsParallel().AsOrdered()
where num % 3 == 0
select num;
// Use foreach to preserve order at execution time.
foreach (var item in parallelQuery)
{
Console.Write($"{item} ");
}
// Some operators expect an ordered source sequence.
var lowValues = parallelQuery.Take(10);
//</snippet12>
}
static void OrderedQuery2()
{
var source = Enumerable.Range(108, 100000);
var parallelQuery =
from num in source.AsParallel().AsOrdered()
where num % 8 == 0
select num;
// use foreach to preserve ordering
// during query execution.
foreach (var item in parallelQuery)
{
Console.Write($"{item} ");
}
}
static void OrderedQuery3()
{
//<Snippet13>
var source = Enumerable.Range(8, 100000);
// Let the query access the data source will full parallelism
// and apply ordering to the filtered results.
var orderedQuery =
from num in source.AsParallel()
where num % 8 == 0
orderby num
select num;
// use foreach to preserve query ordering
foreach (var item in orderedQuery)
{
Console.Write($"{item} ");
}
//</snippet13>
}
}
//<snippet16>
namespace PLINQCancellation_1
{
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static System.Console;
class Program
{
static void Main()
{
int[] source = Enumerable.Range(1, 10000000).ToArray();
using CancellationTokenSource cts = new();
// Start a new asynchronous task that will cancel the
// operation from another thread. Typically you would call
// Cancel() in response to a button click or some other
// user interface event.
Task.Factory.StartNew(() =>
{
UserClicksTheCancelButton(cts);
});
int[]? results = null;
try
{
results =
(from num in source.AsParallel().WithCancellation(cts.Token)
where num % 3 == 0
orderby num descending
select num).ToArray();
}
catch (OperationCanceledException e)
{
WriteLine(e.Message);
}
catch (AggregateException ae)
{
if (ae.InnerExceptions != null)
{
foreach (Exception e in ae.InnerExceptions)
{
WriteLine(e.Message);
}
}
}
foreach (var item in results ?? Array.Empty<int>())
{
WriteLine(item);
}
WriteLine();
ReadKey();
}
static void UserClicksTheCancelButton(CancellationTokenSource cts)
{
// Wait between 150 and 500 ms, then cancel.
// Adjust these values if necessary to make
// cancellation fire while query is still executing.
Random rand = new();
Thread.Sleep(rand.Next(150, 500));
cts.Cancel();
}
}
}
//</snippet16>
//<snippet17>
namespace PLINQCancellation_2
{
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static System.Console;
class Program
{
static void Main(string[] args)
{
int[] source = Enumerable.Range(1, 10000000).ToArray();
using CancellationTokenSource cts = new();
// Start a new asynchronous task that will cancel the
// operation from another thread. Typically you would call
// Cancel() in response to a button click or some other
// user interface event.
Task.Factory.StartNew(() =>
{
UserClicksTheCancelButton(cts);
});
double[]? results = null;
try
{
results =
(from num in source.AsParallel().WithCancellation(cts.Token)
where num % 3 == 0
select Function(num, cts.Token)).ToArray();
}
catch (OperationCanceledException e)
{
WriteLine(e.Message);
}
catch (AggregateException ae)
{
if (ae.InnerExceptions != null)
{
foreach (Exception e in ae.InnerExceptions)
WriteLine(e.Message);
}
}
foreach (var item in results ?? Array.Empty<double>())
{
WriteLine(item);
}
WriteLine();
ReadKey();
}
// A toy method to simulate work.
static double Function(int n, CancellationToken ct)
{
// If work is expected to take longer than 1 ms
// then try to check cancellation status more
// often within that work.
for (int i = 0; i < 5; i++)
{
// Work hard for approx 1 millisecond.
Thread.SpinWait(50000);
// Check for cancellation request.
ct.ThrowIfCancellationRequested();
}
// Anything will do for our purposes.
return Math.Sqrt(n);
}
static void UserClicksTheCancelButton(CancellationTokenSource cts)
{
// Wait between 150 and 500 ms, then cancel.
// Adjust these values if necessary to make
// cancellation fire while query is still executing.
Random rand = new();
Thread.Sleep(rand.Next(150, 500));
WriteLine("Press 'c' to cancel");
if (ReadKey().KeyChar == 'c')
{
cts.Cancel();
}
}
}
}
//</snippet17>
//<snippet18>
namespace PLINQCancellation_3
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
class Program
{
static void Main(string[] args)
{
int[] source = Enumerable.Range(1, 10000000).ToArray();
using CancellationTokenSource cs = new();
IEnumerable<int>? results = null;
try
{
results =
from num in source.AsParallel().WithCancellation(cs.Token)
where num % 3 == 0
orderby num descending
select num;
}
catch (OperationCanceledException e)
{
Console.WriteLine(e.Message);
}
catch (AggregateException ae)
{
if (ae.InnerExceptions != null)
{
foreach (Exception e in ae.InnerExceptions)
Console.WriteLine(e.Message);
}
}
foreach (var item in results ?? Array.Empty<int>())
{
Console.WriteLine(item);
}
Console.WriteLine();
Console.ReadKey();
}
}
}
//</snippet18>
//<snippet23>
namespace MergeOptions
{
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
class Program
{
static void Main(string[] args)
{
var nums = Enumerable.Range(1, 10000);
// Replace NotBuffered with AutoBuffered
// or FullyBuffered to compare behavior.
//<snippet26>
var scanLines = from n in nums.AsParallel()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
where n % 2 == 0
select ExpensiveFunc(n);
//</snippet26>
Stopwatch sw = Stopwatch.StartNew();
foreach (var line in scanLines)
{
Console.WriteLine(line);
}
Console.WriteLine($"Elapsed time: {sw.ElapsedMilliseconds} ms. Press any key to exit.");
Console.ReadKey();
}
// A function that demonstrates what a fly
// sees when it watches television :-)
static string ExpensiveFunc(int i)
{
Thread.SpinWait(2000000);
return string.Format("{0} *****************************************", i);
}
}
}
//</snippet23>
//<snippet31>
namespace PLINQAggregation
{
using System;
using System.Linq;
class aggregation
{
static void Main(string[] args)
{
// Create a data source for demonstration purposes.
int[] source = new int[100000];
Random rand = new Random();
for (int x = 0; x < source.Length; x++)
{
// Should result in a mean of approximately 15.0.
source[x] = rand.Next(10, 20);
}
// Standard deviation calculation requires that we first
// calculate the mean average. Average is a predefined
// aggregation operator, along with Max, Min and Count.
double mean = source.AsParallel().Average();
// We use the overload that is unique to ParallelEnumerable. The
// third Func parameter combines the results from each thread.
double standardDev = source.AsParallel().Aggregate(
// initialize subtotal. Use decimal point to tell
// the compiler this is a type double. Can also use: 0d.
0.0,
// do this on each thread
(subtotal, item) => subtotal + Math.Pow((item - mean), 2),
// aggregate results after all threads are done.
(total, thisThread) => total + thisThread,
// perform standard deviation calc on the aggregated result.
(finalSum) => Math.Sqrt((finalSum / (source.Length - 1)))
);
Console.WriteLine($"Mean value is = {mean}");
Console.WriteLine($"Standard deviation is {standardDev}");
Console.ReadLine();
}
}
}
//</snippet31>
partial class PLINQProgram
{
//} end namespace
}
//<snippet50>
// This class contains a subset of data from the Northwind database
// in the form of string arrays. The methods such as GetCustomers, GetOrders, and so on
// transform the strings into object arrays that you can query in an object-oriented way.
// Many of the code examples in the PLINQ How-to topics are designed to be pasted into
// the PLINQDataSample class and invoked from the Main method.
partial class PLINQDataSample
{
public static void Main()
{
////Call methods here.
TestDataSource();
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
static void TestDataSource()
{
Console.WriteLine($"Customer count: {GetCustomers().Count()}");
Console.WriteLine($"Product count: {GetProducts().Count()}");
Console.WriteLine($"Order count: {GetOrders().Count()}");
Console.WriteLine($"Order Details count: {GetOrderDetails().Count()}");
}
#region DataClasses
public class Order
{
private Lazy<OrderDetail[]> _orderDetails;
public Order()
{
_orderDetails = new Lazy<OrderDetail[]>(() => GetOrderDetailsForOrder(OrderID));
}
public int OrderID { get; set; }
public string? CustomerID { get; set; }
public DateTime OrderDate { get; set; }
public DateTime ShippedDate { get; set; }
public OrderDetail[] OrderDetails { get { return _orderDetails.Value; } }
}
public class Customer
{
private Lazy<Order[]> _orders;
public Customer()
{
_orders = new Lazy<Order[]>(() => GetOrdersForCustomer(CustomerID));
}
public string? CustomerID { get; set; }
public string? CustomerName { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? PostalCode { get; set; }
public Order[] Orders
{
get
{
return _orders.Value;
}
}
}
public class Product
{
public string? ProductName { get; set; }
public int ProductID { get; set; }
public double UnitPrice { get; set; }
}
public class OrderDetail
{
public int OrderID { get; set; }
public int ProductID { get; set; }
public double UnitPrice { get; set; }
public double Quantity { get; set; }
public double Discount { get; set; }
}
#endregion
public static IEnumerable<string> GetCustomersAsStrings()
{
return System.IO.File.ReadAllLines(@"..\..\plinqdata.csv")
.SkipWhile((line) => line.StartsWith("CUSTOMERS") == false)
.Skip(1)
.TakeWhile((line) => line.StartsWith("END CUSTOMERS") == false);
}
public static IEnumerable<Customer> GetCustomers()
{
var customers = System.IO.File.ReadAllLines(@"..\..\plinqdata.csv")
.SkipWhile((line) => line.StartsWith("CUSTOMERS") == false)
.Skip(1)
.TakeWhile((line) => line.StartsWith("END CUSTOMERS") == false);
return (from line in customers
let fields = line.Split(',')
let custID = fields[0].Trim()
select new Customer()
{
CustomerID = custID,
CustomerName = fields[1].Trim(),
Address = fields[2].Trim(),
City = fields[3].Trim(),
PostalCode = fields[4].Trim()
});
}
public static Order[] GetOrdersForCustomer(string? id)
{
// Assumes we copied the file correctly!
var orders = System.IO.File.ReadAllLines(@"..\..\plinqdata.csv")
.SkipWhile((line) => line.StartsWith("ORDERS") == false)
.Skip(1)
.TakeWhile((line) => line.StartsWith("END ORDERS") == false);
var orderStrings = from line in orders
let fields = line.Split(',')
where fields[1].CompareTo(id) == 0
select new Order()
{
OrderID = Convert.ToInt32(fields[0]),
CustomerID = fields[1].Trim(),
OrderDate = DateTime.Parse(fields[2]),
ShippedDate = DateTime.Parse(fields[3])
};
return orderStrings.ToArray();
}
// "10248, VINET, 7/4/1996 12:00:00 AM, 7/16/1996 12:00:00 AM
public static IEnumerable<Order> GetOrders()
{
// Assumes we copied the file correctly!
var orders = System.IO.File.ReadAllLines(@"..\..\plinqdata.csv")
.SkipWhile((line) => line.StartsWith("ORDERS") == false)
.Skip(1)
.TakeWhile((line) => line.StartsWith("END ORDERS") == false);
return from line in orders
let fields = line.Split(',')
select new Order()
{
OrderID = Convert.ToInt32(fields[0]),
CustomerID = fields[1].Trim(),
OrderDate = DateTime.Parse(fields[2]),
ShippedDate = DateTime.Parse(fields[3])
};
}
public static IEnumerable<Product> GetProducts()
{
// Assumes we copied the file correctly!
var products = System.IO.File.ReadAllLines(@"..\..\plinqdata.csv")
.SkipWhile((line) => line.StartsWith("PRODUCTS") == false)
.Skip(1)
.TakeWhile((line) => line.StartsWith("END PRODUCTS") == false);
return from line in products
let fields = line.Split(',')
select new Product()
{
ProductID = Convert.ToInt32(fields[0]),
ProductName = fields[1].Trim(),
UnitPrice = Convert.ToDouble(fields[2])
};
}
public static IEnumerable<OrderDetail> GetOrderDetails()
{
// Assumes we copied the file correctly!
var orderDetails = System.IO.File.ReadAllLines(@"..\..\plinqdata.csv")
.SkipWhile((line) => line.StartsWith("ORDER DETAILS") == false)
.Skip(1)
.TakeWhile((line) => line.StartsWith("END ORDER DETAILS") == false);
return from line in orderDetails
let fields = line.Split(',')
select new OrderDetail()
{
OrderID = Convert.ToInt32(fields[0]),
ProductID = Convert.ToInt32(fields[1]),
UnitPrice = Convert.ToDouble(fields[2]),
Quantity = Convert.ToDouble(fields[3]),
Discount = Convert.ToDouble(fields[4])
};
}
public static OrderDetail[] GetOrderDetailsForOrder(int id)
{
// Assumes we copied the file correctly!
var orderDetails = System.IO.File.ReadAllLines(@"..\..\plinqdata.csv")
.SkipWhile((line) => line.StartsWith("ORDER DETAILS") == false)
.Skip(1)
.TakeWhile((line) => line.StartsWith("END ORDER DETAILS") == false);
var orderDetailStrings = from line in orderDetails
let fields = line.Split(',')
let ordID = Convert.ToInt32(fields[0])
where ordID == id
select new OrderDetail()
{
OrderID = ordID,
ProductID = Convert.ToInt32(fields[1]),
UnitPrice = Convert.ToDouble(fields[2]),
Quantity = Convert.ToDouble(fields[3]),
Discount = Convert.ToDouble(fields[4])
};
return orderDetailStrings.ToArray();
}
}
//</snippet50>
partial class PLINQDataSample
{
//<snippet14>
// Paste into PLINQDataSample class.
static void SimpleOrdering()
{
var customers = GetCustomers();
// Take the first 20, preserving the original order
var firstTwentyCustomers = customers
.AsParallel()
.AsOrdered()
.Take(20);
foreach (var c in firstTwentyCustomers)
Console.Write("{0} ", c.CustomerID);
// All elements in reverse order.
var reverseOrder = customers
.AsParallel()
.AsOrdered()
.Reverse();
foreach (var v in reverseOrder)
Console.Write("{0} ", v.CustomerID);
// Get the element at a specified index.
var cust = customers.AsParallel()
.AsOrdered()
.ElementAt(48);
Console.WriteLine($"Element #48 is: {cust.CustomerID}");
}
//</snippet14>
//<snippet15>
// Paste into PLINQDataSample class.
static void OrderedThenUnordered()
{
var orders = GetOrders();
var orderDetails = GetOrderDetails();
var q2 = orders.AsParallel()
.Where(o => o.OrderDate < DateTime.Parse("07/04/1997"))
.Select(o => o)
.OrderBy(o => o.CustomerID) // Preserve original ordering for Take operation.
.Take(20)
.AsUnordered() // Remove ordering constraint to make join faster.
.Join(
orderDetails.AsParallel(),
ord => ord.OrderID,
od => od.OrderID,
(ord, od) =>
new
{
ID = ord.OrderID,
Customer = ord.CustomerID,
Product = od.ProductID
}
)
.OrderBy(i => i.Product); // Apply new ordering to final result sequence.
foreach (var v in q2)
Console.WriteLine($"{v.ID} {v.Customer} {v.Product}");
}
//</snippet15>
static void NestedLoops()
{
var date = DateTime.Now;
var customers = GetCustomers();
//<snippet20>
var q = from cust in customers.AsParallel()
from order in cust.Orders.AsParallel()
where order.OrderDate > date
select new { cust, order };
//</snippet20>
}
//<snippet22>
// Paste into PLINQDataSample class.
static void ForceParallel()
{
var customers = GetCustomers();
var parallelQuery = (from cust in customers.AsParallel()
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
where cust.City == "Berlin"
select cust.CustomerName)
.ToList();
}
//</snippet22>
//<snippet24>
// Paste into PLINQDataSample class.
static void SequentialDemo()
{
var orders = GetOrders();
var query = (from order in orders.AsParallel()
orderby order.OrderID
select new
{
order.OrderID,
OrderedOn = order.OrderDate,
ShippedOn = order.ShippedDate
})
.AsSequential().Take(5);
}
//</snippet24>
//<snippet25>
class FileIteration
{
static void Main() { }
}
//</snippet25>
//<snippet41>
// Paste into PLINQDataSample class.
static void PLINQExceptions_1()
{
// Using the raw string array here. See PLINQ Data Sample.
string[] customers = GetCustomersAsStrings().ToArray();
// First, we must simulate some corrupt input.
customers[54] = "###";
var parallelQuery = from cust in customers.AsParallel()
let fields = cust.Split(',')
where fields[3].StartsWith("C") //throw indexoutofrange
select new { city = fields[3], thread = Thread.CurrentThread.ManagedThreadId };
try
{
// We use ForAll although it doesn't really improve performance
// since all output is serialized through the Console.
parallelQuery.ForAll(e => Console.WriteLine("City: {0}, Thread:{1}", e.city, e.thread));
}
// In this design, we stop query processing when the exception occurs.
catch (AggregateException e)
{
foreach (var ex in e.InnerExceptions)
{
Console.WriteLine(ex.Message);
if (ex is IndexOutOfRangeException)
Console.WriteLine("The data source is corrupt. Query stopped.");
}
}
}
//</snippet41>
//<snippet42>
// Paste into PLINQDataSample class.
static void PLINQExceptions_2()
{
var customers = GetCustomersAsStrings().ToArray();
// Using the raw string array here.
// First, we must simulate some corrupt input
customers[54] = "###";
// Assume that in this app, we expect malformed data
// occasionally and by design we just report it and continue.
static bool IsTrue(string[] f, string c)
{
try
{
string s = f[3];
return s.StartsWith(c);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine($"Malformed cust: {f}");
return false;
}
};
// Using the raw string array here
var parallelQuery =
from cust in customers.AsParallel()
let fields = cust.Split(',')
where IsTrue(fields, "C") //use a named delegate with a try-catch
select new { City = fields[3] };
try
{
// We use ForAll although it doesn't really improve performance
// since all output must be serialized through the Console.
parallelQuery.ForAll(e => Console.WriteLine(e.City));
}
// IndexOutOfRangeException will not bubble up
// because we handle it where it is thrown.
catch (AggregateException e)
{
foreach (var ex in e.InnerExceptions)
{
Console.WriteLine(ex.Message);
}
}
}
//</snippet42>
}
}sample · vbsamples/snippets/visualbasic/VS_Snippets_Misc/plinq/vb/plinqsnippets1.vb50
Imports System.Threading
Module PLinqSnippetsVB
Sub Main()
Dim x As New IntroSnippet
x.SimpleQuery()
End Sub
Class IntroSnippet
Sub IntroSnippets()
Dim source = Enumerable.Range(1, 10000)
' Opt-in to PLINQ with AsParallel
Dim evenNums = From num In source.AsParallel()
Where Compute(num) > 0
Select num
Console.WriteLine("TBD")
Dim randomValues(1000) As Integer
'Order first, then filter
evenNums = From num In randomValues.AsParallel().AsOrdered()
Where num Mod 2 = 0
Select num
Dim nums = Enumerable.Range(10, 10000)
Dim query = From num In nums.AsParallel()
Where num Mod 10 = 0
Select num
' Process results as each thread completes.
query.ForAll(Sub(e)
Compute(e)
End Sub)
End Sub
Function Compute(ByVal i As Integer) As Integer
Compute = 1
End Function
Sub SimpleQuery()
Dim source = Enumerable.Range(100, 20000)
' Result sequence might be out of order.
Dim parallelQuery = From num In source.AsParallel()
Where num Mod 10 = 0
Select num
' Process result sequence in parallel
parallelQuery.ForAll(Sub(e)
DoSomething(e)
End Sub)
' Or use For Each to merge results first
' as in this example, Where results must
' be serialized sequentially through static Console method.
For Each n In parallelQuery
Console.Write("{0} ", n)
Next
' You can also use ToArray, ToList, etc
' as with LINQ to Objects.
Dim parallelQuery2 = (From num In source.AsParallel()
Where num Mod 10 = 0
Select num).ToArray()
'Method syntax is also supported
Dim parallelQuery3 = source.AsParallel().Where(Function(n)
Return (n Mod 10) = 0
End Function).Select(Function(n)
Return n
End Function)
For Each i As Integer In parallelQuery3
Console.Write("{0} ", i)
Next
Console.ReadLine()
End Sub
' A toy function to demonstrate syntax. Typically you need a more
' computationally expensive method to see speedup over sequential queries.
Sub DoSomething(ByVal i As Integer)
Console.Write("{0:###.## }", Math.Sqrt(i))
End Sub
'<snippet12>
Sub OrderedQuery()
Dim source = Enumerable.Range(9, 10000)
' Source is ordered let's preserve it.
Dim parallelQuery = From num In source.AsParallel().AsOrdered()
Where num Mod 3 = 0
Select num
' Use For Each to preserve order at execution time.
For Each item In parallelQuery
Console.Write("{0} ", item)
Next
' Some operators expect an ordered source sequence.
Dim lowValues = parallelQuery.Take(10)
End Sub
'</snippet12>
'<Snippet13>
Sub OrderedQuery2()
Dim source = Enumerable.Range(8, 100000)
' Let the query access the data source will full parallelism
' and apply ordering to the filtered results.
Dim orderedQuery = From num In source.AsParallel()
Where num Mod 8 = 0
Order By num
Select num
' Use For Each to preserve query ordering.
For Each item In orderedQuery
Console.Write("{0} ", item)
Next
End Sub
'</snippet13>
Sub OrderedQuery3()
Dim source = Enumerable.Range(108, 100000)
Dim parallelQuery = From num In source.AsParallel().AsOrdered()
Where num Mod 8 = 0
Select num
' use For Each to preserve ordering
' during query execution.
For Each item In parallelQuery
Console.Write("{0} ", item)
Next
End Sub
'<snippet16>
Class Program
Private Shared Sub Main(ByVal args As String())
Dim source As Integer() = Enumerable.Range(1, 10000000).ToArray()
Dim cs As New CancellationTokenSource()
' Start a new asynchronous task that will cancel the
' operation from another thread. Typically you would call
' Cancel() in response to a button click or some other
' user interface event.
Task.Factory.StartNew(Sub()
UserClicksTheCancelButton(cs)
End Sub)
Dim results As Integer() = Nothing
Try
results = (From num In source.AsParallel().WithCancellation(cs.Token) _
Where num Mod 3 = 0 _
Order By num Descending _
Select num).ToArray()
Catch e As OperationCanceledException
Console.WriteLine(e.Message)
Catch ae As AggregateException
If ae.InnerExceptions IsNot Nothing Then
For Each e As Exception In ae.InnerExceptions
Console.WriteLine(e.Message)
Next
End If
Finally
cs.Dispose()
End Try
If results IsNot Nothing Then
For Each item In results
Console.WriteLine(item)
Next
End If
Console.WriteLine()
Console.ReadKey()
End Sub
Private Shared Sub UserClicksTheCancelButton(ByVal cs As CancellationTokenSource)
' Wait between 150 and 500 ms, then cancel.
' Adjust these values if necessary to make
' cancellation fire while query is still executing.
Dim rand As New Random()
Thread.Sleep(rand.[Next](150, 350))
cs.Cancel()
End Sub
End Class
'</snippet16>
'<snippet17>
Class Program2
Private Shared Sub Main(ByVal args As String())
Dim source As Integer() = Enumerable.Range(1, 10000000).ToArray()
Dim cs As New CancellationTokenSource()
' Start a new asynchronous task that will cancel the
' operation from another thread. Typically you would call
' Cancel() in response to a button click or some other
' user interface event.
Task.Factory.StartNew(Sub()
UserClicksTheCancelButton(cs)
End Sub)
Dim results As Double() = Nothing
Try
results = (From num In source.AsParallel().WithCancellation(cs.Token) _
Where num Mod 3 = 0 _
Select [Function](num, cs.Token)).ToArray()
Catch e As OperationCanceledException
Console.WriteLine(e.Message)
Catch ae As AggregateException
If ae.InnerExceptions IsNot Nothing Then
For Each e As Exception In ae.InnerExceptions
Console.WriteLine(e.Message)
Next
End If
Finally
cs.Dispose()
End Try
If results IsNot Nothing Then
For Each item In results
Console.WriteLine(item)
Next
End If
Console.WriteLine()
Console.ReadKey()
End Sub
' A toy method to simulate work.
Private Shared Function [Function](ByVal n As Integer, ByVal ct As CancellationToken) As Double
' If work is expected to take longer than 1 ms
' then try to check cancellation status more
' often within that work.
For i As Integer = 0 To 4
' Work hard for approx 1 millisecond.
Thread.SpinWait(50000)
' Check for cancellation request.
If ct.IsCancellationRequested Then
Throw New OperationCanceledException(ct)
End If
Next
' Anything will do for our purposes.
Return Math.Sqrt(n)
End Function
Private Shared Sub UserClicksTheCancelButton(ByVal cs As CancellationTokenSource)
' Wait between 150 and 500 ms, then cancel.
' Adjust these values if necessary to make
' cancellation fire while query is still executing.
Dim rand As New Random()
Thread.Sleep(rand.[Next](150, 350))
Console.WriteLine("Press 'c' to cancel")
If Console.ReadKey().KeyChar = "c"c Then
cs.Cancel()
End If
End Sub
End Class
'</snippet17>
End Class
'<snippet31>
Class aggregation
Private Shared Sub Main(ByVal args As String())
' Create a data source for demonstration purposes.
Dim source As Integer() = New Integer(99999) {}
Dim rand As New Random()
For x As Integer = 0 To source.Length - 1
' Should result in a mean of approximately 15.0.
source(x) = rand.[Next](10, 20)
Next
' Standard deviation calculation requires that we first
' calculate the mean average. Average is a predefined
' aggregation operator, along with Max, Min and Count.
Dim mean As Double = source.AsParallel().Average()
' We use the overload that is unique to ParallelEnumerable. The
' third Func parameter combines the results from each thread.
' initialize subtotal. Use decimal point to tell
' the compiler this is a type double. Can also use: 0d.
' do this on each thread
' aggregate results after all threads are done.
' perform standard deviation calc on the aggregated result.
Dim standardDev As Double = source.AsParallel().Aggregate(0.0R, Function(subtotal, item) subtotal + Math.Pow((item - mean), 2), Function(total, thisThread) total + thisThread, Function(finalSum) Math.Sqrt((finalSum / (source.Length - 1))))
Console.WriteLine("Mean value is = {0}", mean)
Console.WriteLine("Standard deviation is {0}", standardDev)
Console.ReadLine()
End Sub
End Class
'</snippet31>
' <snippet50>
' This class contains a subset of data from the Northwind database
' in the form of string arrays. The methods such as GetCustomers, GetOrders, and so on
' transform the strings into object arrays that you can query in an object-oriented way.
' Many of the code examples in the PLINQ How-to topics are designed to be pasted into
' the PLINQDataSample class and invoked from the Main method.
' IMPORTANT: This data set is not large enough for meaningful comparisons of PLINQ vs. LINQ performance.
Class PLINQDataSample
Shared Sub Main(ByVal args As String())
'Call methods here.
TestDataSource()
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Shared Sub TestDataSource()
Console.WriteLine("Customer count: {0}", GetCustomers().Count())
Console.WriteLine("Product count: {0}", GetProducts().Count())
Console.WriteLine("Order count: {0}", GetOrders().Count())
Console.WriteLine("Order Details count: {0}", GetOrderDetails().Count())
End Sub
#Region "DataClasses"
Class Order
Public Sub New()
_OrderDetails = New Lazy(Of OrderDetail())(Function() GetOrderDetailsForOrder(OrderID))
End Sub
Private _OrderID As Integer
Public Property OrderID() As Integer
Get
Return _OrderID
End Get
Set(ByVal value As Integer)
_OrderID = value
End Set
End Property
Private _CustomerID As String
Public Property CustomerID() As String
Get
Return _CustomerID
End Get
Set(ByVal value As String)
_CustomerID = value
End Set
End Property
Private _OrderDate As DateTime
Public Property OrderDate() As DateTime
Get
Return _OrderDate
End Get
Set(ByVal value As DateTime)
_OrderDate = value
End Set
End Property
Private _ShippedDate As DateTime
Public Property ShippedDate() As DateTime
Get
Return _ShippedDate
End Get
Set(ByVal value As DateTime)
_ShippedDate = value
End Set
End Property
Private _OrderDetails As Lazy(Of OrderDetail())
Public ReadOnly Property OrderDetails As OrderDetail()
Get
Return _OrderDetails.Value
End Get
End Property
End Class
Class Customer
Private _Orders As Lazy(Of Order())
Public Sub New()
_Orders = New Lazy(Of Order())(Function() GetOrdersForCustomer(_CustomerID))
End Sub
Private _CustomerID As String
Public Property CustomerID() As String
Get
Return _CustomerID
End Get
Set(ByVal value As String)
_CustomerID = value
End Set
End Property
Private _CustomerName As String
Public Property CustomerName() As String
Get
Return _CustomerName
End Get
Set(ByVal value As String)
_CustomerName = value
End Set
End Property
Private _Address As String
Public Property Address() As String
Get
Return _Address
End Get
Set(ByVal value As String)
_Address = value
End Set
End Property
Private _City As String
Public Property City() As String
Get
Return _City
End Get
Set(ByVal value As String)
_City = value
End Set
End Property
Private _PostalCode As String
Public Property PostalCode() As String
Get
Return _PostalCode
End Get
Set(ByVal value As String)
_PostalCode = value
End Set
End Property
Public ReadOnly Property Orders() As Order()
Get
Return _Orders.Value
End Get
End Property
End Class
Class Product
Private _ProductName As String
Public Property ProductName() As String
Get
Return _ProductName
End Get
Set(ByVal value As String)
_ProductName = value
End Set
End Property
Private _ProductID As Integer
Public Property ProductID() As Integer
Get
Return _ProductID
End Get
Set(ByVal value As Integer)
_ProductID = value
End Set
End Property
Private _UnitPrice As Double
Public Property UnitPrice() As Double
Get
Return _UnitPrice
End Get
Set(ByVal value As Double)
_UnitPrice = value
End Set
End Property
End Class
Class OrderDetail
Private _OrderID As Integer
Public Property OrderID() As Integer
Get
Return _OrderID
End Get
Set(ByVal value As Integer)
_OrderID = value
End Set
End Property
Private _ProductID As Integer
Public Property ProductID() As Integer
Get
Return _ProductID
End Get
Set(ByVal value As Integer)
_ProductID = value
End Set
End Property
Private _UnitPrice As Double
Public Property UnitPrice() As Double
Get
Return _UnitPrice
End Get
Set(ByVal value As Double)
_UnitPrice = value
End Set
End Property
Private _Quantity As Double
Public Property Quantity() As Double
Get
Return _Quantity
End Get
Set(ByVal value As Double)
_Quantity = value
End Set
End Property
Private _Discount As Double
Public Property Discount() As Double
Get
Return _Discount
End Get
Set(ByVal value As Double)
_Discount = value
End Set
End Property
End Class
#End Region
Shared Function GetCustomersAsStrings() As IEnumerable(Of String)
Return IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("CUSTOMERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END CUSTOMERS") = False)
End Function
Shared Function GetCustomers() As IEnumerable(Of Customer)
Dim customers = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("CUSTOMERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END CUSTOMERS") = False)
Return From line In customers
Let fields = line.Split(","c)
Select New Customer With {
.CustomerID = fields(0).Trim(),
.CustomerName = fields(1).Trim(),
.Address = fields(2).Trim(),
.City = fields(3).Trim(),
.PostalCode = fields(4).Trim()}
End Function
Shared Function GetOrders() As IEnumerable(Of Order)
Dim orders = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDERS") = False)
Return From line In orders
Let fields = line.Split(","c)
Select New Order With {
.OrderID = CType(fields(0).Trim(), Integer),
.CustomerID = fields(1).Trim(),
.OrderDate = DateTime.Parse(fields(2)),
.ShippedDate = DateTime.Parse(fields(3))}
End Function
Shared Function GetOrdersForCustomer(ByVal id As String) As Order()
Dim orders = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDERS") = False)
Dim orderStrings = From line In orders
Let fields = line.Split(","c)
Let custID = fields(1).Trim()
Where custID = id
Select New Order With {
.OrderID = CType(fields(0).Trim(), Integer),
.CustomerID = custID,
.OrderDate = DateTime.Parse(fields(2)),
.ShippedDate = DateTime.Parse(fields(3))}
Return orderStrings.ToArray()
End Function
Shared Function GetProducts() As IEnumerable(Of Product)
Dim products = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("PRODUCTS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END PRODUCTS") = False)
Return From line In products
Let fields = line.Split(","c)
Select New Product With {
.ProductID = CType(fields(0), Integer),
.ProductName = fields(1).Trim(),
.UnitPrice = CType(fields(2), Double)}
End Function
Shared Function GetOrderDetailsForOrder(ByVal orderID As Integer) As OrderDetail()
Dim orderDetails = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDER DETAILS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDER DETAILS") = False)
Dim ordDetailStrings = From line In orderDetails
Let fields = line.Split(","c)
Let ordID = Convert.ToInt32(fields(0))
Where ordID = orderID
Select New OrderDetail With {
.OrderID = ordID,
.ProductID = CType(fields(1), Integer),
.UnitPrice = CType(fields(2), Double),
.Quantity = CType(fields(3), Double),
.Discount = CType(fields(4), Double)}
Return ordDetailStrings.ToArray()
End Function
Shared Function GetOrderDetails() As IEnumerable(Of OrderDetail)
Dim orderDetails = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDER DETAILS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDER DETAILS") = False)
Return From line In orderDetails
Let fields = line.Split(","c)
Select New OrderDetail With {
.OrderID = CType(fields(0), Integer),
.ProductID = CType(fields(1), Integer),
.UnitPrice = CType(fields(2), Double),
.Quantity = CType(fields(3), Double),
.Discount = CType(fields(4), Double)}
End Function
End Class
'</snippet50>
' This class duplicates snippet50 but we use it to embed methods that we don't want to show
' up in the published file, (because they have their own files) but we need them to compile as if they are members of this class.
Class PLINQDataSample_InternalForCompilingSomeSnippets
Shared Sub Main(ByVal args As String())
'Call methods here.
TestDataSource()
Dim p As New PLINQDataSample_InternalForCompilingSomeSnippets
PLINQExceptions_1()
' p.OrderedThenUnordered()
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Shared Sub TestDataSource()
Console.WriteLine("Customer count: {0}", GetCustomers().Count())
Console.WriteLine("Product count: {0}", GetProducts().Count())
Console.WriteLine("Order count: {0}", GetOrders().Count())
Console.WriteLine("Order Details count: {0}", GetOrderDetails().Count())
End Sub
'<snippet14>
' Paste into PLINQDataSample class
Shared Sub SimpleOrdering()
Dim customers As List(Of Customer) = GetCustomers().ToList()
' Take the first 20, preserving the original order
Dim firstTwentyCustomers = customers _
.AsParallel() _
.AsOrdered() _
.Take(20)
Console.WriteLine("Take the first 20 in original order")
For Each c As Customer In firstTwentyCustomers
Console.Write(c.CustomerID & " ")
Next
' All elements in reverse order.
Dim reverseOrder = customers _
.AsParallel() _
.AsOrdered() _
.Reverse()
Console.WriteLine(vbCrLf & "Take all elements in reverse order")
For Each c As Customer In reverseOrder
Console.Write("{0} ", c.CustomerID)
Next
' Get the element at a specified index.
Dim cust = customers.AsParallel() _
.AsOrdered() _
.ElementAt(48)
Console.WriteLine("Element #48 is: " & cust.CustomerID)
End Sub
'</snippet14>
'<snippet15>
' Paste into PLINQDataSample class
Sub OrderedThenUnordered()
Dim Orders As IEnumerable(Of Order) = GetOrders()
Dim orderDetails As IEnumerable(Of OrderDetail) = GetOrderDetails()
' Sometimes it's easier to create a query
' by composing two subqueries
Dim query1 = From ord In Orders.AsParallel()
Where ord.OrderDate < DateTime.Parse("07/04/1997")
Select ord
Order By ord.CustomerID
Take 20
Dim query2 = From ord In query1.AsUnordered()
Join od In orderDetails.AsParallel() On ord.OrderID Equals od.OrderID
Order By od.ProductID
Select New With {ord.OrderID, ord.CustomerID, od.ProductID}
For Each item In query2
Console.WriteLine("{0} {1} {2}", item.OrderID, item.CustomerID, item.ProductID)
Next
End Sub
'</snippet15>
'<snippet22>
Private Shared Sub ForceParallel()
Dim customers = GetCustomers()
Dim parallelQuery = (From cust In customers.AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism)
Where cust.City = "Berlin"
Select cust.CustomerName).ToList()
End Sub
'</snippet22>
'<snippet24>
' Paste into PLINQDataSample class
Shared Sub SequentialDemo()
Dim orders = GetOrders()
Dim query = From ord In orders.AsParallel()
Order By ord.OrderID
Select New With
{
ord.OrderID,
ord.OrderDate,
ord.ShippedDate
}
Dim query2 = query.AsSequential().Take(5)
For Each item In query2
Console.WriteLine("{0}, {1}, {2}", item.OrderDate, item.OrderID, item.ShippedDate)
Next
End Sub
'</snippet24>
'<snippet25>
Class FileIteration
Shared Sub Main()
End Sub
End Class
'</snippet25>
'<snippet41>
' Paste into PLINQDataSample class
Shared Sub PLINQExceptions_1()
' Using the raw string array here. See PLINQ Data Sample.
Dim customers As String() = GetCustomersAsStrings().ToArray()
' First, we must simulate some corrupt input.
customers(20) = "###"
'throws indexoutofrange
Dim query = From cust In customers.AsParallel()
Let fields = cust.Split(","c)
Where fields(3).StartsWith("C")
Select fields
Try
' We use ForAll although it doesn't really improve performance
' since all output is serialized through the Console.
query.ForAll(Sub(e)
Console.WriteLine("City: {0}, Thread:{1}")
End Sub)
Catch e As AggregateException
' In this design, we stop query processing when the exception occurs.
For Each ex In e.InnerExceptions
Console.WriteLine(ex.Message)
If TypeOf ex Is IndexOutOfRangeException Then
Console.WriteLine("The data source is corrupt. Query stopped.")
End If
Next
End Try
End Sub
'</snippet41>
'<snippet42>
' Paste into PLINQDataSample class
Shared Sub PLINQExceptions_2()
Dim customers() = GetCustomersAsStrings().ToArray()
' Using the raw string array here.
' First, we must simulate some corrupt input
customers(20) = "###"
' Create a delegate with a lambda expression.
' Assume that in this app, we expect malformed data
' occasionally and by design we just report it and continue.
Dim isTrue As Func(Of String(), String, Boolean) = Function(f, c)
Try
Dim s As String = f(3)
Return s.StartsWith(c)
Catch e As IndexOutOfRangeException
Console.WriteLine("Malformed cust: {0}", f)
Return False
End Try
End Function
' Using the raw string array here
Dim query = From cust In customers.AsParallel()
Let fields = cust.Split(","c)
Where isTrue(fields, "C")
Select New With {.City = fields(3)}
Try
' We use ForAll although it doesn't really improve performance
' since all output must be serialized through the Console.
query.ForAll(Sub(e) Console.WriteLine(e.City))
' IndexOutOfRangeException will not bubble up
' because we handle it where it is thrown.
Catch e As AggregateException
For Each ex In e.InnerExceptions
Console.WriteLine(ex.Message)
Next
End Try
End Sub
'</snippet42>
#Region "DataClasses"
Class Order
Public Sub New()
_OrderDetails = New Lazy(Of OrderDetail())(Function() GetOrderDetailsForOrder(OrderID))
End Sub
Private _OrderID As Integer
Public Property OrderID() As Integer
Get
Return _OrderID
End Get
Set(ByVal value As Integer)
_OrderID = value
End Set
End Property
Private _CustomerID As String
Public Property CustomerID() As String
Get
Return _CustomerID
End Get
Set(ByVal value As String)
_CustomerID = value
End Set
End Property
Private _OrderDate As DateTime
Public Property OrderDate() As DateTime
Get
Return _OrderDate
End Get
Set(ByVal value As DateTime)
_OrderDate = value
End Set
End Property
Private _ShippedDate As DateTime
Public Property ShippedDate() As DateTime
Get
Return _ShippedDate
End Get
Set(ByVal value As DateTime)
_ShippedDate = value
End Set
End Property
Private _OrderDetails As Lazy(Of OrderDetail())
Public ReadOnly Property OrderDetails As OrderDetail()
Get
Return _OrderDetails.Value
End Get
End Property
End Class
Class Customer
Private _Orders As Lazy(Of Order())
Public Sub New()
_Orders = New Lazy(Of Order())(Function() GetOrdersForCustomer(_CustomerID))
End Sub
Private _CustomerID As String
Public Property CustomerID() As String
Get
Return _CustomerID
End Get
Set(ByVal value As String)
_CustomerID = value
End Set
End Property
Private _CustomerName As String
Public Property CustomerName() As String
Get
Return _CustomerName
End Get
Set(ByVal value As String)
_CustomerName = value
End Set
End Property
Private _Address As String
Public Property Address() As String
Get
Return _Address
End Get
Set(ByVal value As String)
_Address = value
End Set
End Property
Private _City As String
Public Property City() As String
Get
Return _City
End Get
Set(ByVal value As String)
_City = value
End Set
End Property
Private _PostalCode As String
Public Property PostalCode() As String
Get
Return _PostalCode
End Get
Set(ByVal value As String)
_PostalCode = value
End Set
End Property
Public ReadOnly Property Orders() As Order()
Get
Return _Orders.Value
End Get
End Property
End Class
Class Product
Private _ProductName As String
Public Property ProductName() As String
Get
Return _ProductName
End Get
Set(ByVal value As String)
_ProductName = value
End Set
End Property
Private _ProductID As Integer
Public Property ProductID() As Integer
Get
Return _ProductID
End Get
Set(ByVal value As Integer)
_ProductID = value
End Set
End Property
Private _UnitPrice As Double
Public Property UnitPrice() As Double
Get
Return _UnitPrice
End Get
Set(ByVal value As Double)
_UnitPrice = value
End Set
End Property
End Class
Class OrderDetail
Private _OrderID As Integer
Public Property OrderID() As Integer
Get
Return _OrderID
End Get
Set(ByVal value As Integer)
_OrderID = value
End Set
End Property
Private _ProductID As Integer
Public Property ProductID() As Integer
Get
Return _ProductID
End Get
Set(ByVal value As Integer)
_ProductID = value
End Set
End Property
Private _UnitPrice As Double
Public Property UnitPrice() As Double
Get
Return _UnitPrice
End Get
Set(ByVal value As Double)
_UnitPrice = value
End Set
End Property
Private _Quantity As Double
Public Property Quantity() As Double
Get
Return _Quantity
End Get
Set(ByVal value As Double)
_Quantity = value
End Set
End Property
Private _Discount As Double
Public Property Discount() As Double
Get
Return _Discount
End Get
Set(ByVal value As Double)
_Discount = value
End Set
End Property
End Class
#End Region
#Region "DataMethods"
Shared Function GetCustomersAsStrings() As IEnumerable(Of String)
Return IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("CUSTOMERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END CUSTOMERS") = False)
End Function
Shared Function GetCustomers() As IEnumerable(Of Customer)
Dim customers = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("CUSTOMERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END CUSTOMERS") = False)
Return From line In customers
Let fields = line.Split(","c)
Select New Customer With {
.CustomerID = fields(0).Trim(),
.CustomerName = fields(1).Trim(),
.Address = fields(2).Trim(),
.City = fields(3).Trim(),
.PostalCode = fields(4).Trim()}
End Function
Shared Function GetOrders() As IEnumerable(Of Order)
Dim orders = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDERS") = False)
Return From line In orders
Let fields = line.Split(","c)
Select New Order With {
.OrderID = CType(fields(0).Trim(), Integer),
.CustomerID = fields(1).Trim(),
.OrderDate = DateTime.Parse(fields(2)),
.ShippedDate = DateTime.Parse(fields(3))}
End Function
Shared Function GetOrdersForCustomer(ByVal id As String) As Order()
Dim orders = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDERS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDERS") = False)
Dim orderStrings = From line In orders
Let fields = line.Split(","c)
Let custID = fields(1).Trim()
Where custID = id
Select New Order With {
.OrderID = CType(fields(0).Trim(), Integer),
.CustomerID = custID,
.OrderDate = DateTime.Parse(fields(2)),
.ShippedDate = DateTime.Parse(fields(3))}
Return orderStrings.ToArray()
End Function
Shared Function GetProducts() As IEnumerable(Of Product)
Dim products = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("PRODUCTS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END PRODUCTS") = False)
Return From line In products
Let fields = line.Split(","c)
Select New Product With {
.ProductID = CType(fields(0), Integer),
.ProductName = fields(1).Trim(),
.UnitPrice = CType(fields(2), Double)}
End Function
Shared Function GetOrderDetailsForOrder(ByVal orderID As Integer) As OrderDetail()
Dim orderDetails = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDER DETAILS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDER DETAILS") = False)
Dim ordDetailStrings = From line In orderDetails
Let fields = line.Split(","c)
Let ordID = Convert.ToInt32(fields(0))
Where ordID = orderID
Select New OrderDetail With {
.OrderID = ordID,
.ProductID = CType(fields(1), Integer),
.UnitPrice = CType(fields(2), Double),
.Quantity = CType(fields(3), Double),
.Discount = CType(fields(4), Double)}
Return ordDetailStrings.ToArray()
End Function
Shared Function GetOrderDetails() As IEnumerable(Of OrderDetail)
Dim orderDetails = IO.File.ReadAllLines("..\..\plinqdata.csv").
SkipWhile(Function(line) line.StartsWith("ORDER DETAILS") = False).
Skip(1).
TakeWhile(Function(line) line.StartsWith("END ORDER DETAILS") = False)
Return From line In orderDetails
Let fields = line.Split(","c)
Select New OrderDetail With {
.OrderID = CType(fields(0), Integer),
.ProductID = CType(fields(1), Integer),
.UnitPrice = CType(fields(2), Double),
.Quantity = CType(fields(3), Double),
.Discount = CType(fields(4), Double)}
End Function
#End Region
End Class
End ModuleData
CUSTOMERS
ALFKI,Alfreds Futterkiste,Obere Str. 57,Berlin,12209
ANATR,Ana Trujillo Emparedados y helados,Avda. de la Constitución 2222,México D.F.,05021
ANTON,Antonio Moreno Taquería,Mataderos 2312,México D.F.,05023
AROUT,Around the Horn,120 Hanover Sq.,London,WA1 1DP
BERGS,Berglunds snabbköp,Berguvsvägen 8,Luleå,S-958 22
BLAUS,Blauer See Delikatessen,Forsterstr. 57,Mannheim,68306
BLONP,Blondesddsl père et fils,24, place Kléber,Strasbourg,67000
BOLID,Bólido Comidas preparadas,C/ Araquil, 67,Madrid,28023
BONAP,Bon app',12, rue des Bouchers,Marseille,13008
BOTTM,Bottom-Dollar Markets,23 Tsawassen Blvd.,Tsawassen,T2F 8M4
BSBEV,B's Beverages,Fauntleroy Circus,London,EC2 5NT
CACTU,Cactus Comidas para llevar,Cerrito 333,Buenos Aires,1010
CENTC,Centro comercial Moctezuma,Sierras de Granada 9993,México D.F.,05022
CHOPS,Chop-suey Chinese,Hauptstr. 29,Bern,3012
COMMI,Comércio Mineiro,Av. dos Lusíadas, 23,Sao Paulo,05432-043
CONSH,Consolidated Holdings,Berkeley Gardens 12 Brewery,London,WX1 6LT
DRACD,Drachenblut Delikatessen,Walserweg 21,Aachen,52066
DUMON,Du monde entier,67, rue des Cinquante Otages,Nantes,44000
EASTC,Eastern Connection,35 King George,London,WX3 6FW
ERNSH,Ernst Handel,Kirchgasse 6,Graz,8010
FAMIA,Familia Arquibaldo,Rua Orós, 92,Sao Paulo,05442-030
FISSA,FISSA Fabrica Inter. Salchichas S.A.,C/ Moralzarzal, 86,Madrid,28034
FOLIG,Folies gourmandes,184, chaussée de Tournai,Lille,59000
FOLKO,Folk och fä HB,Åkergatan 24,Bräcke,S-844 67
FRANK,Frankenversand,Berliner Platz 43,München,80805
FRANR,France restauration,54, rue Royale,Nantes,44000
FRANS,Franchi S.p.A.,Via Monte Bianco 34,Torino,10100
FURIB,Furia Bacalhau e Frutos do Mar,Jardim das rosas n. 32,Lisboa,1675
GALED,Galería del gastrónomo,Rambla de Cataluña, 23,Barcelona,08022
GODOS,Godos Cocina Típica,C/ Romero, 33,Sevilla,41101
GOURL,Gourmet Lanchonetes,Av. Brasil, 442,Campinas,04876-786
GREAL,Great Lakes Food Market,2732 Baker Blvd.,Eugene,97403
GROSR,GROSELLA-Restaurante,5ª Ave. Los Palos Grandes,Caracas,1081
HANAR,Hanari Carnes,Rua do Paço, 67,Rio de Janeiro,05454-876
HILAA,HILARION-Abastos,Carrera 22 con Ave. Carlos Soublette #8-35,San Cristóbal,5022
HUNGC,Hungry Coyote Import Store,City Center Plaza 516 Main St.,Elgin,97827
HUNGO,Hungry Owl All-Night Grocers,8 Johnstown Road,Cork,
ISLAT,Island Trading,Garden House Crowther Way,Cowes,PO31 7PJ
KOENE,Königlich Essen,Maubelstr. 90,Brandenburg,14776
LACOR,La corne d'abondance,67, avenue de l'Europe,Versailles,78000
LAMAI,La maison d'Asie,1 rue Alsace-Lorraine,Toulouse,31000
LAUGB,Laughing Bacchus Wine Cellars,1900 Oak St.,Vancouver,V3F 2K1
LAZYK,Lazy K Kountry Store,12 Orchestra Terrace,Walla Walla,99362
LEHMS,Lehmanns Marktstand,Magazinweg 7,Frankfurt a.M.,60528
LETSS,Let's Stop N Shop,87 Polk St. Suite 5,San Francisco,94117
LILAS,LILA-Supermercado,Carrera 52 con Ave. Bolívar #65-98 Llano Largo,Barquisimeto,3508
LINOD,LINO-Delicateses,Ave. 5 de Mayo Porlamar,I. de Margarita,4980
LONEP,Lonesome Pine Restaurant,89 Chiaroscuro Rd.,Portland,97219
MAGAA,Magazzini Alimentari Riuniti,Via Ludovico il Moro 22,Bergamo,24100
MAISD,Maison Dewey,Rue Joseph-Bens 532,Bruxelles,B-1180
END CUSTOMERS
ORDERS
10250,HANAR,7/8/1996 12:00:00 AM,7/12/1996 12:00:00 AM
10253,HANAR,7/10/1996 12:00:00 AM,7/16/1996 12:00:00 AM
10254,CHOPS,7/11/1996 12:00:00 AM,7/23/1996 12:00:00 AM
10257,HILAA,7/16/1996 12:00:00 AM,7/22/1996 12:00:00 AM
10258,ERNSH,7/17/1996 12:00:00 AM,7/23/1996 12:00:00 AM
10263,ERNSH,7/23/1996 12:00:00 AM,7/31/1996 12:00:00 AM
10264,FOLKO,7/24/1996 12:00:00 AM,8/23/1996 12:00:00 AM
10265,BLONP,7/25/1996 12:00:00 AM,8/12/1996 12:00:00 AM
10267,FRANK,7/29/1996 12:00:00 AM,8/6/1996 12:00:00 AM
10275,MAGAA,8/7/1996 12:00:00 AM,8/9/1996 12:00:00 AM
10278,BERGS,8/12/1996 12:00:00 AM,8/16/1996 12:00:00 AM
10279,LEHMS,8/13/1996 12:00:00 AM,8/16/1996 12:00:00 AM
10280,BERGS,8/14/1996 12:00:00 AM,9/12/1996 12:00:00 AM
10283,LILAS,8/16/1996 12:00:00 AM,8/23/1996 12:00:00 AM
10284,LEHMS,8/19/1996 12:00:00 AM,8/27/1996 12:00:00 AM
10289,BSBEV,8/26/1996 12:00:00 AM,8/28/1996 12:00:00 AM
10290,COMMI,8/27/1996 12:00:00 AM,9/3/1996 12:00:00 AM
10296,LILAS,9/3/1996 12:00:00 AM,9/11/1996 12:00:00 AM
10297,BLONP,9/4/1996 12:00:00 AM,9/10/1996 12:00:00 AM
10298,HUNGO,9/5/1996 12:00:00 AM,9/11/1996 12:00:00 AM
10300,MAGAA,9/9/1996 12:00:00 AM,9/18/1996 12:00:00 AM
10303,GODOS,9/11/1996 12:00:00 AM,9/18/1996 12:00:00 AM
10307,LONEP,9/17/1996 12:00:00 AM,9/25/1996 12:00:00 AM
10309,HUNGO,9/19/1996 12:00:00 AM,10/23/1996 12:00:00 AM
10315,ISLAT,9/26/1996 12:00:00 AM,10/3/1996 12:00:00 AM
10317,LONEP,9/30/1996 12:00:00 AM,10/10/1996 12:00:00 AM
10318,ISLAT,10/1/1996 12:00:00 AM,10/4/1996 12:00:00 AM
10321,ISLAT,10/3/1996 12:00:00 AM,10/11/1996 12:00:00 AM
10323,KOENE,10/7/1996 12:00:00 AM,10/14/1996 12:00:00 AM
10325,KOENE,10/9/1996 12:00:00 AM,10/14/1996 12:00:00 AM
10327,FOLKO,10/11/1996 12:00:00 AM,10/14/1996 12:00:00 AM
10328,FURIB,10/14/1996 12:00:00 AM,10/17/1996 12:00:00 AM
10330,LILAS,10/16/1996 12:00:00 AM,10/28/1996 12:00:00 AM
10331,BONAP,10/16/1996 12:00:00 AM,10/21/1996 12:00:00 AM
10335,HUNGO,10/22/1996 12:00:00 AM,10/24/1996 12:00:00 AM
10337,FRANK,10/24/1996 12:00:00 AM,10/29/1996 12:00:00 AM
10340,BONAP,10/29/1996 12:00:00 AM,11/8/1996 12:00:00 AM
10342,FRANK,10/30/1996 12:00:00 AM,11/4/1996 12:00:00 AM
10343,LEHMS,10/31/1996 12:00:00 AM,11/6/1996 12:00:00 AM
10347,FAMIA,11/6/1996 12:00:00 AM,11/8/1996 12:00:00 AM
10350,LAMAI,11/11/1996 12:00:00 AM,12/3/1996 12:00:00 AM
10351,ERNSH,11/11/1996 12:00:00 AM,11/20/1996 12:00:00 AM
10352,FURIB,11/12/1996 12:00:00 AM,11/18/1996 12:00:00 AM
10355,AROUT,11/15/1996 12:00:00 AM,11/20/1996 12:00:00 AM
10357,LILAS,11/19/1996 12:00:00 AM,12/2/1996 12:00:00 AM
10358,LAMAI,11/20/1996 12:00:00 AM,11/27/1996 12:00:00 AM
10360,BLONP,11/22/1996 12:00:00 AM,12/2/1996 12:00:00 AM
10362,BONAP,11/25/1996 12:00:00 AM,11/28/1996 12:00:00 AM
10363,DRACD,11/26/1996 12:00:00 AM,12/4/1996 12:00:00 AM
10364,EASTC,11/26/1996 12:00:00 AM,12/4/1996 12:00:00 AM
10365,ANTON,11/27/1996 12:00:00 AM,12/2/1996 12:00:00 AM
10366,GALED,11/28/1996 12:00:00 AM,12/30/1996 12:00:00 AM
10368,ERNSH,11/29/1996 12:00:00 AM,12/2/1996 12:00:00 AM
10370,CHOPS,12/3/1996 12:00:00 AM,12/27/1996 12:00:00 AM
10371,LAMAI,12/3/1996 12:00:00 AM,12/24/1996 12:00:00 AM
10373,HUNGO,12/5/1996 12:00:00 AM,12/11/1996 12:00:00 AM
10375,HUNGC,12/6/1996 12:00:00 AM,12/9/1996 12:00:00 AM
10378,FOLKO,12/10/1996 12:00:00 AM,12/19/1996 12:00:00 AM
10380,HUNGO,12/12/1996 12:00:00 AM,1/16/1997 12:00:00 AM
10381,LILAS,12/12/1996 12:00:00 AM,12/13/1996 12:00:00 AM
10382,ERNSH,12/13/1996 12:00:00 AM,12/16/1996 12:00:00 AM
10383,AROUT,12/16/1996 12:00:00 AM,12/18/1996 12:00:00 AM
10384,BERGS,12/16/1996 12:00:00 AM,12/20/1996 12:00:00 AM
10386,FAMIA,12/18/1996 12:00:00 AM,12/25/1996 12:00:00 AM
10389,BOTTM,12/20/1996 12:00:00 AM,12/24/1996 12:00:00 AM
10391,DRACD,12/23/1996 12:00:00 AM,12/31/1996 12:00:00 AM
10394,HUNGC,12/25/1996 12:00:00 AM,1/3/1997 12:00:00 AM
10395,HILAA,12/26/1996 12:00:00 AM,1/3/1997 12:00:00 AM
10396,FRANK,12/27/1996 12:00:00 AM,1/6/1997 12:00:00 AM
10400,EASTC,1/1/1997 12:00:00 AM,1/16/1997 12:00:00 AM
10404,MAGAA,1/3/1997 12:00:00 AM,1/8/1997 12:00:00 AM
10405,LINOD,1/6/1997 12:00:00 AM,1/22/1997 12:00:00 AM
10408,FOLIG,1/8/1997 12:00:00 AM,1/14/1997 12:00:00 AM
10410,BOTTM,1/10/1997 12:00:00 AM,1/15/1997 12:00:00 AM
10411,BOTTM,1/10/1997 12:00:00 AM,1/21/1997 12:00:00 AM
10413,LAMAI,1/14/1997 12:00:00 AM,1/16/1997 12:00:00 AM
10414,FAMIA,1/14/1997 12:00:00 AM,1/17/1997 12:00:00 AM
10415,HUNGC,1/15/1997 12:00:00 AM,1/24/1997 12:00:00 AM
10422,FRANS,1/22/1997 12:00:00 AM,1/31/1997 12:00:00 AM
10423,GOURL,1/23/1997 12:00:00 AM,2/24/1997 12:00:00 AM
10425,LAMAI,1/24/1997 12:00:00 AM,2/14/1997 12:00:00 AM
10426,GALED,1/27/1997 12:00:00 AM,2/6/1997 12:00:00 AM
10431,BOTTM,1/30/1997 12:00:00 AM,2/7/1997 12:00:00 AM
10434,FOLKO,2/3/1997 12:00:00 AM,2/13/1997 12:00:00 AM
10436,BLONP,2/5/1997 12:00:00 AM,2/11/1997 12:00:00 AM
10444,BERGS,2/12/1997 12:00:00 AM,2/21/1997 12:00:00 AM
10445,BERGS,2/13/1997 12:00:00 AM,2/20/1997 12:00:00 AM
10449,BLONP,2/18/1997 12:00:00 AM,2/27/1997 12:00:00 AM
10453,AROUT,2/21/1997 12:00:00 AM,2/26/1997 12:00:00 AM
10456,KOENE,2/25/1997 12:00:00 AM,2/28/1997 12:00:00 AM
10457,KOENE,2/25/1997 12:00:00 AM,3/3/1997 12:00:00 AM
10460,FOLKO,2/28/1997 12:00:00 AM,3/3/1997 12:00:00 AM
10464,FURIB,3/4/1997 12:00:00 AM,3/14/1997 12:00:00 AM
10466,COMMI,3/6/1997 12:00:00 AM,3/13/1997 12:00:00 AM
10467,MAGAA,3/6/1997 12:00:00 AM,3/11/1997 12:00:00 AM
10468,KOENE,3/7/1997 12:00:00 AM,3/12/1997 12:00:00 AM
10470,BONAP,3/11/1997 12:00:00 AM,3/14/1997 12:00:00 AM
10471,BSBEV,3/11/1997 12:00:00 AM,3/18/1997 12:00:00 AM
10473,ISLAT,3/13/1997 12:00:00 AM,3/21/1997 12:00:00 AM
10476,HILAA,3/17/1997 12:00:00 AM,3/24/1997 12:00:00 AM
10480,FOLIG,3/20/1997 12:00:00 AM,3/24/1997 12:00:00 AM
10484,BSBEV,3/24/1997 12:00:00 AM,4/1/1997 12:00:00 AM
10485,LINOD,3/25/1997 12:00:00 AM,3/31/1997 12:00:00 AM
10486,HILAA,3/26/1997 12:00:00 AM,4/2/1997 12:00:00 AM
10488,FRANK,3/27/1997 12:00:00 AM,4/2/1997 12:00:00 AM
10490,HILAA,3/31/1997 12:00:00 AM,4/3/1997 12:00:00 AM
10491,FURIB,3/31/1997 12:00:00 AM,4/8/1997 12:00:00 AM
10492,BOTTM,4/1/1997 12:00:00 AM,4/11/1997 12:00:00 AM
10494,COMMI,4/2/1997 12:00:00 AM,4/9/1997 12:00:00 AM
10497,LEHMS,4/4/1997 12:00:00 AM,4/7/1997 12:00:00 AM
10501,BLAUS,4/9/1997 12:00:00 AM,4/16/1997 12:00:00 AM
10507,ANTON,4/15/1997 12:00:00 AM,4/22/1997 12:00:00 AM
10509,BLAUS,4/17/1997 12:00:00 AM,4/29/1997 12:00:00 AM
10511,BONAP,4/18/1997 12:00:00 AM,4/21/1997 12:00:00 AM
10512,FAMIA,4/21/1997 12:00:00 AM,4/24/1997 12:00:00 AM
10519,CHOPS,4/28/1997 12:00:00 AM,5/1/1997 12:00:00 AM
10521,CACTU,4/29/1997 12:00:00 AM,5/2/1997 12:00:00 AM
10522,LEHMS,4/30/1997 12:00:00 AM,5/6/1997 12:00:00 AM
10528,GREAL,5/6/1997 12:00:00 AM,5/9/1997 12:00:00 AM
10529,MAISD,5/7/1997 12:00:00 AM,5/9/1997 12:00:00 AM
10532,EASTC,5/9/1997 12:00:00 AM,5/12/1997 12:00:00 AM
10535,ANTON,5/13/1997 12:00:00 AM,5/21/1997 12:00:00 AM
10538,BSBEV,5/15/1997 12:00:00 AM,5/16/1997 12:00:00 AM
10539,BSBEV,5/16/1997 12:00:00 AM,5/23/1997 12:00:00 AM
10541,HANAR,5/19/1997 12:00:00 AM,5/29/1997 12:00:00 AM
10544,LONEP,5/21/1997 12:00:00 AM,5/30/1997 12:00:00 AM
10550,GODOS,5/28/1997 12:00:00 AM,6/6/1997 12:00:00 AM
10551,FURIB,5/28/1997 12:00:00 AM,6/6/1997 12:00:00 AM
10558,AROUT,6/4/1997 12:00:00 AM,6/10/1997 12:00:00 AM
10568,GALED,6/13/1997 12:00:00 AM,7/9/1997 12:00:00 AM
10573,ANTON,6/19/1997 12:00:00 AM,6/20/1997 12:00:00 AM
10581,FAMIA,6/26/1997 12:00:00 AM,7/2/1997 12:00:00 AM
10582,BLAUS,6/27/1997 12:00:00 AM,7/14/1997 12:00:00 AM
10589,GREAL,7/4/1997 12:00:00 AM,7/14/1997 12:00:00 AM
10600,HUNGC,7/16/1997 12:00:00 AM,7/21/1997 12:00:00 AM
10614,BLAUS,7/29/1997 12:00:00 AM,8/1/1997 12:00:00 AM
10616,GREAL,7/31/1997 12:00:00 AM,8/5/1997 12:00:00 AM
10617,GREAL,7/31/1997 12:00:00 AM,8/4/1997 12:00:00 AM
10621,ISLAT,8/5/1997 12:00:00 AM,8/11/1997 12:00:00 AM
10629,GODOS,8/12/1997 12:00:00 AM,8/20/1997 12:00:00 AM
10634,FOLIG,8/15/1997 12:00:00 AM,8/21/1997 12:00:00 AM
10635,MAGAA,8/18/1997 12:00:00 AM,8/21/1997 12:00:00 AM
10638,LINOD,8/20/1997 12:00:00 AM,9/1/1997 12:00:00 AM
10643,ALFKI,8/25/1997 12:00:00 AM,9/2/1997 12:00:00 AM
10645,HANAR,8/26/1997 12:00:00 AM,9/2/1997 12:00:00 AM
10649,MAISD,8/28/1997 12:00:00 AM,8/29/1997 12:00:00 AM
10652,GOURL,9/1/1997 12:00:00 AM,9/8/1997 12:00:00 AM
10656,GREAL,9/4/1997 12:00:00 AM,9/10/1997 12:00:00 AM
10660,HUNGC,9/8/1997 12:00:00 AM,10/15/1997 12:00:00 AM
10662,LONEP,9/9/1997 12:00:00 AM,9/18/1997 12:00:00 AM
10665,LONEP,9/11/1997 12:00:00 AM,9/17/1997 12:00:00 AM
10677,ANTON,9/22/1997 12:00:00 AM,9/26/1997 12:00:00 AM
10685,GOURL,9/29/1997 12:00:00 AM,10/3/1997 12:00:00 AM
10690,HANAR,10/2/1997 12:00:00 AM,10/3/1997 12:00:00 AM
10692,ALFKI,10/3/1997 12:00:00 AM,10/13/1997 12:00:00 AM
10697,LINOD,10/8/1997 12:00:00 AM,10/14/1997 12:00:00 AM
10702,ALFKI,10/13/1997 12:00:00 AM,10/21/1997 12:00:00 AM
10707,AROUT,10/16/1997 12:00:00 AM,10/23/1997 12:00:00 AM
10709,GOURL,10/17/1997 12:00:00 AM,11/20/1997 12:00:00 AM
10710,FRANS,10/20/1997 12:00:00 AM,10/23/1997 12:00:00 AM
10726,EASTC,11/3/1997 12:00:00 AM,12/5/1997 12:00:00 AM
10729,LINOD,11/4/1997 12:00:00 AM,11/14/1997 12:00:00 AM
10731,CHOPS,11/6/1997 12:00:00 AM,11/14/1997 12:00:00 AM
10734,GOURL,11/7/1997 12:00:00 AM,11/12/1997 12:00:00 AM
10746,CHOPS,11/19/1997 12:00:00 AM,11/21/1997 12:00:00 AM
10753,FRANS,11/25/1997 12:00:00 AM,11/27/1997 12:00:00 AM
10760,MAISD,12/1/1997 12:00:00 AM,12/10/1997 12:00:00 AM
10763,FOLIG,12/3/1997 12:00:00 AM,12/8/1997 12:00:00 AM
10782,CACTU,12/17/1997 12:00:00 AM,12/22/1997 12:00:00 AM
10789,FOLIG,12/22/1997 12:00:00 AM,12/31/1997 12:00:00 AM
10797,DRACD,12/25/1997 12:00:00 AM,1/5/1998 12:00:00 AM
10807,FRANS,12/31/1997 12:00:00 AM,1/30/1998 12:00:00 AM
10819,CACTU,1/7/1998 12:00:00 AM,1/16/1998 12:00:00 AM
10825,DRACD,1/9/1998 12:00:00 AM,1/14/1998 12:00:00 AM
10835,ALFKI,1/15/1998 12:00:00 AM,1/21/1998 12:00:00 AM
10853,BLAUS,1/27/1998 12:00:00 AM,2/3/1998 12:00:00 AM
10872,GODOS,2/5/1998 12:00:00 AM,2/9/1998 12:00:00 AM
10874,GODOS,2/6/1998 12:00:00 AM,2/11/1998 12:00:00 AM
10881,CACTU,2/11/1998 12:00:00 AM,2/18/1998 12:00:00 AM
10887,GALED,2/13/1998 12:00:00 AM,2/16/1998 12:00:00 AM
10892,MAISD,2/17/1998 12:00:00 AM,2/19/1998 12:00:00 AM
10896,MAISD,2/19/1998 12:00:00 AM,2/27/1998 12:00:00 AM
10928,GALED,3/5/1998 12:00:00 AM,3/18/1998 12:00:00 AM
10937,CACTU,3/10/1998 12:00:00 AM,3/13/1998 12:00:00 AM
10952,ALFKI,3/16/1998 12:00:00 AM,3/24/1998 12:00:00 AM
10969,COMMI,3/23/1998 12:00:00 AM,3/30/1998 12:00:00 AM
10987,EASTC,3/31/1998 12:00:00 AM,4/6/1998 12:00:00 AM
11026,FRANS,4/15/1998 12:00:00 AM,4/28/1998 12:00:00 AM
11036,DRACD,4/20/1998 12:00:00 AM,4/22/1998 12:00:00 AM
11042,COMMI,4/22/1998 12:00:00 AM,5/1/1998 12:00:00 AM
END ORDERS
ORDER DETAILS
10250,41,7.7000,10,0
10250,51,42.4000,35,0.15
10250,65,16.8000,15,0.15
10253,31,10.0000,20,0
10253,39,14.4000,42,0
10253,49,16.0000,40,0
10254,24,3.6000,15,0.15
10254,55,19.2000,21,0.15
10254,74,8.0000,21,0
10257,27,35.1000,25,0
10257,39,14.4000,6,0
10257,77,10.4000,15,0
10258,2,15.2000,50,0.2
10258,5,17.0000,65,0.2
10258,32,25.6000,6,0.2
10263,16,13.9000,60,0.25
10263,24,3.6000,28,0
10263,30,20.7000,60,0.25
10263,74,8.0000,36,0.25
10264,2,15.2000,35,0
10264,41,7.7000,25,0.15
10265,17,31.2000,30,0
10265,70,12.0000,20,0
10267,40,14.7000,50,0
10267,59,44.0000,70,0.15
10267,76,14.4000,15,0.15
10275,24,3.6000,12,0.05
10275,59,44.0000,6,0.05
10278,44,15.5000,16,0
10278,59,44.0000,15,0
10278,63,35.1000,8,0
10278,73,12.0000,25,0
10279,17,31.2000,15,0.25
10280,24,3.6000,12,0
10280,55,19.2000,20,0
10280,75,6.2000,30,0
10283,15,12.4000,20,0
10283,19,7.3000,18,0
10283,60,27.2000,35,0
10283,72,27.8000,3,0
10284,27,35.1000,15,0.25
10284,44,15.5000,21,0
10284,60,27.2000,20,0.25
10284,67,11.2000,5,0.25
10289,3,8.0000,30,0
10289,64,26.6000,9,0
10290,5,17.0000,20,0
10290,29,99.0000,15,0
10290,49,16.0000,15,0
10290,77,10.4000,10,0
10296,11,16.8000,12,0
10296,16,13.9000,30,0
10296,69,28.8000,15,0
10297,39,14.4000,60,0
10297,72,27.8000,20,0
10298,2,15.2000,40,0
10298,36,15.2000,40,0.25
10298,59,44.0000,30,0.25
10298,62,39.4000,15,0
10300,66,13.6000,30,0
10300,68,10.0000,20,0
10303,40,14.7000,40,0.1
10303,65,16.8000,30,0.1
10303,68,10.0000,15,0.1
10307,62,39.4000,10,0
10307,68,10.0000,3,0
10309,4,17.6000,20,0
10309,6,20.0000,30,0
10309,42,11.2000,2,0
10309,43,36.8000,20,0
10309,71,17.2000,3,0
10315,34,11.2000,14,0
10315,70,12.0000,30,0
10317,1,14.4000,20,0
10318,41,7.7000,20,0
10318,76,14.4000,6,0
10321,35,14.4000,10,0
10323,15,12.4000,5,0
10323,25,11.2000,4,0
10323,39,14.4000,4,0
10325,6,20.0000,6,0
10325,13,4.8000,12,0
10325,14,18.6000,9,0
10325,31,10.0000,4,0
10325,72,27.8000,40,0
10327,2,15.2000,25,0.2
10327,11,16.8000,50,0.2
10327,30,20.7000,35,0.2
10327,58,10.6000,30,0.2
10328,59,44.0000,9,0
10328,65,16.8000,40,0
10328,68,10.0000,10,0
10330,26,24.9000,50,0.15
10330,72,27.8000,25,0.15
10331,54,5.9000,15,0
10335,2,15.2000,7,0.2
10335,31,10.0000,25,0.2
10335,32,25.6000,6,0.2
10335,51,42.4000,48,0.2
10337,23,7.2000,40,0
10337,26,24.9000,24,0
10337,36,15.2000,20,0
10337,37,20.8000,28,0
10337,72,27.8000,25,0
10340,18,50.0000,20,0.05
10340,41,7.7000,12,0.05
10340,43,36.8000,40,0.05
10342,2,15.2000,24,0.2
10342,31,10.0000,56,0.2
10342,36,15.2000,40,0.2
10342,55,19.2000,40,0.2
10343,64,26.6000,50,0
10343,68,10.0000,4,0.05
10343,76,14.4000,15,0
10347,25,11.2000,10,0
10347,39,14.4000,50,0.15
10347,40,14.7000,4,0
10347,75,6.2000,6,0.15
10350,50,13.0000,15,0.1
10350,69,28.8000,18,0.1
10351,38,210.8000,20,0.05
10351,41,7.7000,13,0
10351,44,15.5000,77,0.05
10351,65,16.8000,10,0.05
10352,24,3.6000,10,0
10352,54,5.9000,20,0.15
10355,24,3.6000,25,0
10355,57,15.6000,25,0
10357,10,24.8000,30,0.2
10357,26,24.9000,16,0
10357,60,27.2000,8,0.2
10358,24,3.6000,10,0.05
10358,34,11.2000,10,0.05
10358,36,15.2000,20,0.05
10360,28,36.4000,30,0
10360,29,99.0000,35,0
10360,38,210.8000,10,0
10360,49,16.0000,35,0
10360,54,5.9000,28,0
10362,25,11.2000,50,0
10362,51,42.4000,20,0
10362,54,5.9000,24,0
10363,31,10.0000,20,0
10363,75,6.2000,12,0
10363,76,14.4000,12,0
10364,69,28.8000,30,0
10364,71,17.2000,5,0
10365,11,16.8000,24,0
10366,65,16.8000,5,0
10366,77,10.4000,5,0
10368,21,8.0000,5,0.1
10368,28,36.4000,13,0.1
10368,57,15.6000,25,0
10368,64,26.6000,35,0.1
10370,1,14.4000,15,0.15
10370,64,26.6000,30,0
10370,74,8.0000,20,0.15
10371,36,15.2000,6,0.2
10373,58,10.6000,80,0.2
10373,71,17.2000,50,0.2
10375,14,18.6000,15,0
10375,54,5.9000,10,0
10378,71,17.2000,6,0
10380,30,20.7000,18,0.1
10380,53,26.2000,20,0.1
10380,60,27.2000,6,0.1
10380,70,12.0000,30,0
10381,74,8.0000,14,0
10382,5,17.0000,32,0
10382,18,50.0000,9,0
10382,29,99.0000,14,0
10382,33,2.0000,60,0
10382,74,8.0000,50,0
10383,13,4.8000,20,0
10383,50,13.0000,15,0
10383,56,30.4000,20,0
10384,20,64.8000,28,0
10384,60,27.2000,15,0
10386,24,3.6000,15,0
10386,34,11.2000,10,0
10389,10,24.8000,16,0
10389,55,19.2000,15,0
10389,62,39.4000,20,0
10389,70,12.0000,30,0
10391,13,4.8000,18,0
10394,13,4.8000,10,0
10394,62,39.4000,10,0
10395,46,9.6000,28,0.1
10395,53,26.2000,70,0.1
10395,69,28.8000,8,0
10396,23,7.2000,40,0
10396,71,17.2000,60,0
10396,72,27.8000,21,0
10400,29,99.0000,21,0
10400,35,14.4000,35,0
10400,49,16.0000,30,0
10404,26,24.9000,30,0.05
10404,42,11.2000,40,0.05
10404,49,16.0000,30,0.05
10405,3,8.0000,50,0
10408,37,20.8000,10,0
10408,54,5.9000,6,0
10408,62,39.4000,35,0
10410,33,2.0000,49,0
10410,59,44.0000,16,0
10411,41,7.7000,25,0.2
10411,44,15.5000,40,0.2
10411,59,44.0000,9,0.2
10413,1,14.4000,24,0
10413,62,39.4000,40,0
10413,76,14.4000,14,0
10414,19,7.3000,18,0.05
10414,33,2.0000,50,0
10415,17,31.2000,2,0
10415,33,2.0000,20,0
10422,26,24.9000,2,0
10423,31,10.0000,14,0
10423,59,44.0000,20,0
10425,55,19.2000,10,0.25
10425,76,14.4000,20,0.25
10426,56,30.4000,5,0
10426,64,26.6000,7,0
10431,17,31.2000,50,0.25
10431,40,14.7000,50,0.25
10431,47,7.6000,30,0.25
10434,11,16.8000,6,0
10434,76,14.4000,18,0.15
10436,46,9.6000,5,0
10436,56,30.4000,40,0.1
10436,64,26.6000,30,0.1
10436,75,6.2000,24,0.1
10444,17,31.2000,10,0
10444,26,24.9000,15,0
10444,35,14.4000,8,0
10444,41,7.7000,30,0
10445,39,14.4000,6,0
10445,54,5.9000,15,0
10449,10,24.8000,14,0
10449,52,5.6000,20,0
10449,62,39.4000,35,0
10453,48,10.2000,15,0.1
10453,70,12.0000,25,0.1
10456,21,8.0000,40,0.15
10456,49,16.0000,21,0.15
10457,59,44.0000,36,0
10460,68,10.0000,21,0.25
10460,75,6.2000,4,0.25
10464,4,17.6000,16,0.2
10464,43,36.8000,3,0
10464,56,30.4000,30,0.2
10464,60,27.2000,20,0
10466,11,16.8000,10,0
10466,46,9.6000,5,0
10467,24,3.6000,28,0
10467,25,11.2000,12,0
10468,30,20.7000,8,0
10468,43,36.8000,15,0
10470,18,50.0000,30,0
10470,23,7.2000,15,0
10470,64,26.6000,8,0
10471,7,24.0000,30,0
10471,56,30.4000,20,0
10473,33,2.0000,12,0
10473,71,17.2000,12,0
10476,55,19.2000,2,0.05
10476,70,12.0000,12,0
10480,47,7.6000,30,0
10480,59,44.0000,12,0
10484,21,8.0000,14,0
10484,40,14.7000,10,0
10484,51,42.4000,3,0
10485,2,15.2000,20,0.1
10485,3,8.0000,20,0.1
10485,55,19.2000,30,0.1
10485,70,12.0000,60,0.1
10486,11,16.8000,5,0
10486,51,42.4000,25,0
10486,74,8.0000,16,0
10488,59,44.0000,30,0
10488,73,12.0000,20,0.2
10490,59,44.0000,60,0
10490,68,10.0000,30,0
10490,75,6.2000,36,0
10491,44,15.5000,15,0.15
10491,77,10.4000,7,0.15
10492,25,11.2000,60,0.05
10492,42,11.2000,20,0.05
10494,56,30.4000,30,0
10497,56,30.4000,14,0
10497,72,27.8000,25,0
10497,77,10.4000,25,0
10501,54,7.4500,20,0
10507,43,46.0000,15,0.15
10507,48,12.7500,15,0.15
10509,28,45.6000,3,0
10511,4,22.0000,50,0.15
10511,7,30.0000,50,0.15
10511,8,40.0000,10,0.15
10512,24,4.5000,10,0.15
10512,46,12.0000,9,0.15
10512,47,9.5000,6,0.15
10512,60,34.0000,12,0.15
10519,10,31.0000,16,0.05
10519,56,38.0000,40,0
10519,60,34.0000,10,0.05
10521,35,18.0000,3,0
10521,41,9.6500,10,0
10521,68,12.5000,6,0
10522,1,18.0000,40,0.2
10522,8,40.0000,24,0
10522,30,25.8900,20,0.2
10522,40,18.4000,25,0.2
10528,11,21.0000,3,0
10528,33,2.5000,8,0.2
10528,72,34.8000,9,0
10529,55,24.0000,14,0
10529,68,12.5000,20,0
10529,69,36.0000,10,0
10532,30,25.8900,15,0
10532,66,17.0000,24,0
10535,11,21.0000,50,0.1
10535,40,18.4000,10,0.1
10535,57,19.5000,5,0.1
10535,59,55.0000,15,0.1
10538,70,15.0000,7,0
10538,72,34.8000,1,0
10539,13,6.0000,8,0
10539,21,10.0000,15,0
10539,33,2.5000,15,0
10539,49,20.0000,6,0
10541,24,4.5000,35,0.1
10541,38,263.5000,4,0.1
10541,65,21.0500,36,0.1
10541,71,21.5000,9,0.1
10544,28,45.6000,7,0
10544,67,14.0000,7,0
10550,17,39.0000,8,0.1
10550,19,9.2000,10,0
10550,21,10.0000,6,0.1
10550,61,28.5000,10,0.1
10551,16,17.4500,40,0.15
10551,35,18.0000,20,0.15
10551,44,19.4500,40,0
10558,47,9.5000,25,0
10558,51,53.0000,20,0
10558,52,7.0000,30,0
10558,53,32.8000,18,0
10558,73,15.0000,3,0
10568,10,31.0000,5,0
10573,17,39.0000,18,0
10573,34,14.0000,40,0
10573,53,32.8000,25,0
10581,75,7.7500,50,0.2
10582,57,19.5000,4,0
10582,76,18.0000,14,0
10589,35,18.0000,4,0
10600,54,7.4500,4,0
10600,73,15.0000,30,0
10614,11,21.0000,14,0
10614,21,10.0000,8,0
10614,39,18.0000,5,0
10616,38,263.5000,15,0.05
10616,56,38.0000,14,0
10616,70,15.0000,15,0.05
10616,71,21.5000,15,0.05
10617,59,55.0000,30,0.15
10621,19,9.2000,5,0
10621,23,9.0000,10,0
10621,70,15.0000,20,0
10621,71,21.5000,15,0
10629,29,123.7900,20,0
10629,64,33.2500,9,0
10634,7,30.0000,35,0
10634,18,62.5000,50,0
10634,51,53.0000,15,0
10634,75,7.7500,2,0
10635,4,22.0000,10,0.1
10635,5,21.3500,15,0.1
10635,22,21.0000,40,0
10638,45,9.5000,20,0
10638,65,21.0500,21,0
10638,72,34.8000,60,0
10643,28,45.6000,15,0.25
10643,39,18.0000,21,0.25
10643,46,12.0000,2,0.25
10645,18,62.5000,20,0
10645,36,19.0000,15,0
10649,28,45.6000,20,0
10649,72,34.8000,15,0
10652,30,25.8900,2,0.25
10652,42,14.0000,20,0
10656,14,23.2500,3,0.1
10656,44,19.4500,28,0.1
10656,47,9.5000,6,0.1
10660,20,81.0000,21,0
10662,68,12.5000,10,0
10665,51,53.0000,20,0
10665,59,55.0000,1,0
10665,76,18.0000,10,0
10677,26,31.2300,30,0.15
10677,33,2.5000,8,0.15
10685,10,31.0000,20,0
10685,41,9.6500,4,0
10685,47,9.5000,15,0
10690,56,38.0000,20,0.25
10690,77,13.0000,30,0.25
10692,63,43.9000,20,0
10697,19,9.2000,7,0.25
10697,35,18.0000,9,0.25
10697,58,13.2500,30,0.25
10697,70,15.0000,30,0.25
10702,3,10.0000,6,0
10702,76,18.0000,15,0
10707,55,24.0000,21,0
10707,57,19.5000,40,0
10707,70,15.0000,28,0.15
10709,8,40.0000,40,0
10709,51,53.0000,28,0
10709,60,34.0000,10,0
10710,19,9.2000,5,0
10710,47,9.5000,5,0
10726,4,22.0000,25,0
10726,11,21.0000,5,0
10729,1,18.0000,50,0
10729,21,10.0000,30,0
10729,50,16.2500,40,0
10731,21,10.0000,40,0.05
10731,51,53.0000,30,0.05
10734,6,25.0000,30,0
10734,30,25.8900,15,0
10734,76,18.0000,20,0
10746,13,6.0000,6,0
10746,42,14.0000,28,0
10746,62,49.3000,9,0
10746,69,36.0000,40,0
10753,45,9.5000,4,0
10753,74,10.0000,5,0
10760,25,14.0000,12,0.25
10760,27,43.9000,40,0
10760,43,46.0000,30,0.25
10763,21,10.0000,40,0
10763,22,21.0000,6,0
10763,24,4.5000,20,0
10782,31,12.5000,1,0
10789,18,62.5000,30,0
10789,35,18.0000,15,0
10789,63,43.9000,30,0
10789,68,12.5000,18,0
10797,11,21.0000,20,0
10807,40,18.4000,1,0
10819,43,46.0000,7,0
10819,75,7.7500,20,0
10825,26,31.2300,12,0
10825,53,32.8000,20,0
10835,59,55.0000,15,0
10835,77,13.0000,2,0.2
10853,18,62.5000,10,0
10872,55,24.0000,10,0.05
10872,62,49.3000,20,0.05
10872,64,33.2500,15,0.05
10872,65,21.0500,21,0.05
10874,10,31.0000,10,0
10881,73,15.0000,10,0
10887,25,14.0000,5,0
10892,59,55.0000,40,0.05
10896,45,9.5000,15,0
10896,56,38.0000,16,0
10928,47,9.5000,5,0
10928,76,18.0000,5,0
10937,28,45.6000,8,0
10937,34,14.0000,20,0
10952,6,25.0000,16,0.05
10952,28,45.6000,2,0
10969,46,12.0000,9,0
10987,7,30.0000,60,0
10987,43,46.0000,6,0
10987,72,34.8000,20,0
11026,18,62.5000,8,0
11026,51,53.0000,10,0
11036,13,6.0000,7,0
11036,59,55.0000,30,0
11042,44,19.4500,15,0
11042,61,28.5000,4,0
END ORDER DETAILS
PRODUCTS
1,Chai,18.0000
2,Chang,19.0000
3,Aniseed Syrup,10.0000
4,Chef Anton's Cajun Seasoning,22.0000
5,Chef Anton's Gumbo Mix,21.3500
6,Grandma's Boysenberry Spread,25.0000
7,Uncle Bob's Organic Dried Pears,30.0000
8,Northwoods Cranberry Sauce,40.0000
9,Mishi Kobe Niku,97.0000
10,Ikura,31.0000
11,Queso Cabrales,21.0000
12,Queso Manchego La Pastora,38.0000
13,Konbu,6.0000
14,Tofu,23.2500
15,Genen Shouyu,15.5000
16,Pavlova,17.4500
17,Alice Mutton,39.0000
18,Carnarvon Tigers,62.5000
19,Teatime Chocolate Biscuits,9.2000
20,Sir Rodney's Marmalade,81.0000
21,Sir Rodney's Scones,10.0000
22,Gustaf's Knäckebröd,21.0000
23,Tunnbröd,9.0000
24,Guaraná Fantástica,4.5000
25,NuNuCa Nuß-Nougat-Creme,14.0000
26,Gumbär Gummibärchen,31.2300
27,Schoggi Schokolade,43.9000
28,Rössle Sauerkraut,45.6000
29,Thüringer Rostbratwurst,123.7900
30,Nord-Ost Matjeshering,25.8900
31,Gorgonzola Telino,12.5000
32,Mascarpone Fabioli,32.0000
33,Geitost,2.5000
34,Sasquatch Ale,14.0000
35,Steeleye Stout,18.0000
36,Inlagd Sill,19.0000
37,Gravad lax,26.0000
38,Côte de Blaye,263.5000
39,Chartreuse verte,18.0000
40,Boston Crab Meat,18.4000
41,Jack's New England Clam Chowder,9.6500
42,Singaporean Hokkien Fried Mee,14.0000
43,Ipoh Coffee,46.0000
44,Gula Malacca,19.4500
45,Rogede sild,9.5000
46,Spegesild,12.0000
47,Zaanse koeken,9.5000
48,Chocolade,12.7500
49,Maxilaku,20.0000
50,Valkoinen suklaa,16.2500
51,Manjimup Dried Apples,53.0000
52,Filo Mix,7.0000
53,Perth Pasties,32.8000
54,Tourtière,7.4500
55,Pâté chinois,24.0000
56,Gnocchi di nonna Alice,38.0000
57,Ravioli Angelo,19.5000
58,Escargots de Bourgogne,13.2500
59,Raclette Courdavault,55.0000
60,Camembert Pierrot,34.0000
61,Sirop d'érable,28.5000
62,Tarte au sucre,49.3000
63,Vegie-spread,43.9000
64,Wimmers gute Semmelknödel,33.2500
65,Louisiana Fiery Hot Pepper Sauce,21.0500
66,Louisiana Hot Spiced Okra,17.0000
67,Laughing Lumberjack Lager,14.0000
68,Scottish Longbreads,12.5000
69,Gudbrandsdalsost,36.0000
70,Outback Lager,15.0000
71,Flotemysost,21.5000
72,Mozzarella di Giovanni,34.8000
73,Röd Kaviar,15.0000
74,Longlife Tofu,10.0000
75,Rhönbräu Klosterbier,7.7500
76,Lakkalikööri,18.0000
77,Original Frankfurter grüne Soße,13.0000
END PRODUCTS