Skip to content

Instantly share code, notes, and snippets.

@yallie
Last active December 31, 2015 23:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yallie/8063411 to your computer and use it in GitHub Desktop.
Save yallie/8063411 to your computer and use it in GitHub Desktop.
Zyan+EF6+SqlCe4 concurrent data access example. Application source code (make sure you create a configuration file).
// Zyan + EF6 concurrent data access example.
// Written by Alexey Yakovlev <yallie@yandex.ru>
// Compile this code using:
//
// csc eftest3.cs /r:Zyan.Communication.dll /r:EntityFramework.dll /r:EntityFramework.SqlServerCompact.dll /r:System.ComponentModel.DataAnnotations.dll
//
// First run — starts server.
// Second run — starts client.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Transactions;
using Zyan.Communication;
using Zyan.Communication.Protocols.Tcp;
class Program
{
static void Main(string[] args)
{
try
{
RunServer();
}
catch (SocketException) // server already running
{
RunClient();
}
}
// shared code ---------------
interface IUserService
{
void AddUser(string name);
IEnumerable<string> GetUsers();
}
// server code ---------------
class User
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
class UserContext : DbContext
{
public DbSet<User> Users { get; set; }
}
class UserService : IUserService
{
public void AddUser(string name)
{
Console.WriteLine("Adding user: {0}", name);
var user = new User { Name = name };
userContext.Users.Add(user);
userContext.SaveChanges();
if (name == "Dave")
{
// even if SaveChanges is already called, the transaction will be rolled back due to exception
throw new InvalidOperationException("I'm sorry Dave, I'm afraid I can't do that.");
}
}
public IEnumerable<string> GetUsers()
{
var query =
from u in userContext.Users
orderby u.Name
select u.Name;
return query.ToArray();
}
}
static void RunServer()
{
using (var zyanHost = new ZyanComponentHost("EntityFrameworkServer", 8195))
{
zyanHost.RegisterComponent<IUserService, UserService>();
zyanHost.BeforeInvoke += ZyanHost_BeforeInvoke;
zyanHost.AfterInvoke += ZyanHost_AfterInvoke;
zyanHost.InvokeCanceled += ZyanHost_InvokeCanceled;
Console.WriteLine("Trying to access the database...");
using (var ctx = new UserContext())
{
var dummy = ctx.Users.Count();
}
Console.WriteLine("Server is ready. Press ENTER to stop.");
Console.WriteLine();
Console.WriteLine("Run the program again to test the concurrent database access.");
Console.ReadLine();
}
}
[ThreadStatic]
static UserContext userContext;
[ThreadStatic]
static TransactionScope transactionScope;
static void ZyanHost_BeforeInvoke(object sender, BeforeInvokeEventArgs args)
{
var options = new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
Timeout = TimeSpan.Zero
};
// begin a new transaction and create a data context
transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, options);
userContext = new UserContext();
}
static void ZyanHost_AfterInvoke(object sender, AfterInvokeEventArgs args)
{
// remote call was successful, commit the transaction
if (transactionScope != null)
{
transactionScope.Complete();
transactionScope.Dispose();
transactionScope = null;
}
if (userContext != null)
{
userContext.Dispose();
userContext = null;
}
}
static void ZyanHost_InvokeCanceled(object sender, InvokeCanceledEventArgs args)
{
// remote call failed, rollback the transaction
if (transactionScope != null)
{
transactionScope.Dispose();
transactionScope = null;
}
if (userContext != null)
{
userContext.Dispose();
userContext = null;
}
}
// client code ---------------
static void RunClient()
{
var serverUrl = "tcp://localhost:8195/EntityFrameworkServer";
Console.WriteLine("Connecting to {0}...", serverUrl);
Console.WriteLine();
using (var zyanConnection = new ZyanConnection(serverUrl))
{
var proxy = zyanConnection.CreateProxy<IUserService>();
// inserting data concurrently
Console.WriteLine("Spawning several threads to create multiple users...");
var userNames = new[] { "Bob", "Alice", "Dave", "Erwin", "Charles", "Roger", "Steve" };
for (var i = 0; i < 20; i++)
{
var index = i;
ThreadPool.QueueUserWorkItem(x =>
{
var name = userNames[index % userNames.Length];
Console.WriteLine("Adding {0}...", name);
try
{
proxy.AddUser(name);
}
catch (Exception ex)
{
Console.WriteLine("Error inserting {0}. {1}", name, ex.InnerException.Message);
}
});
}
Console.WriteLine("Wait a minute, then press ENTER to continue.");
Console.ReadLine();
// selecting data
var users = proxy.GetUsers();
Console.WriteLine("{0} users in the database: {1}", users.Count(), string.Join(", ", users));
Console.WriteLine();
Console.WriteLine("Notice there are no Daves.");
Console.ReadLine();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment