Skip to content

Instantly share code, notes, and snippets.

@Thorium
Created February 19, 2013 19:28
Show Gist options
  • Save Thorium/4989024 to your computer and use it in GitHub Desktop.
Save Thorium/4989024 to your computer and use it in GitHub Desktop.
Example of state of the art C#: EntityFramework done right... :-)
// This shows how you can:
// 1) Code from top-down, give high level picture first and then go to details
// 2) Define LINQ outside EF-context and still convert it to SQL:
// - Don't hammer the database!
// 3) Have small independend classes (/parts)
// 4) Have state-less code with no global/class-variables outside entities
// 5) Easy to test:
// - Integration test with EF-DbContext.
// - LINQ logics unit tests without DbContext (with unit tests InternalsVisibleToAttribute).
// 6) Code declarative and functional C#
// (Applying some F#-language concepts to C#. Like function composition and partial application)
/// <summary> Some simple EF domain item for this example</summary>
public class MyItem
{
public string Name { get; set; }
public int Age { get; set; }
public string AccountNumber { get; set; }
}
/// <summary> Some simple EF DBContext item for this example </summary>
public class MyDbContext : DbContext
{
public MyDbContext() : base("myConnectionString") { }
public DbSet<MyItem> MyItems;
}
/// <summary>
/// The first class that user should open when opening solution...
/// This gives you the high level business-oriented picture (with minimal .NET-implementation details)
/// </summary>
public static class Program
{
/// <summary> Top-down coding: High leven picture </summary>
public static void HighLevelBusinessPicture()
{
var res = MyBusinessOperation
.DefineMyBusinessAsLinq()
.DefineSomeMoreBusinessAsLinq()
.DoSomethingAndExecuteAll();
}
}
internal static class MyBusinessOperation
{
/// <summary> This is pure EF wihout context. </summary>
/// <returns> Returns a function which input is Context.DbSet items, output is result as Queryable</returns>
internal static Func<IQueryable<MyItem>, IQueryable<string>> DefineMyBusinessAsLinq()
{
return items =>
{
var namesAndAccounts =
from i in items
where i.Age > 10
select new {i.Name, i.AccountNumber}; // (note: EF-limitation: no complex objects here...)
var externals =
from pair in namesAndAccounts
where !string.IsNullOrEmpty(pair.AccountNumber)
select pair.AccountNumber;
return externals;
};
}
}
/// <summary> Some other independend operation. </summary>
internal static class MyBusinessOperation2
{
/// <summary> Again, the same pattern here! </summary>
internal static Func<IQueryable<MyItem>, IQueryable<string>> DefineSomeMoreBusinessAsLinq(this Func<IQueryable<MyItem>, IQueryable<string>> accountNumbers)
{
return items =>
{
var res = from acc in accountNumbers(items)
let externalAccount = "External " + acc
select externalAccount;
return res;
};
}
}
/// <summary> Then, after everything is ok, we will </summary>
internal static class MyBusinessOperation3
{
internal static IEnumerable<string> DoSomethingAndExecuteAll(this Func<IQueryable<MyItem>, IQueryable<string>> inputs)
{
using (var context = new MyDbContext())
{
var execute = inputs(context.MyItems.AsQueryable());
return execute.ToList();
}
}
// /// <summary> Or EntityFramework 6 Asyc version, await when needed: </summary>
//public async static Task<IEnumerable<string>> DoSomethingAndExecuteAll(this Func<IQueryable<MyItem>, IQueryable<string>> inputs)
//{
// using (var context = new MyDbContext())
// {
// var execute = inputs(context.MyItems.AsQueryable());
// return await execute.ToListAsync().ContinueWith(r => r.Result.AsEnumerable());
// }
//}
}
///// <summary>
///// Example of unit test
///// </summary>
//[TestClass]
//public class MyBusinessOperation2Fixture
//{
// [TestMethod]
// public void DefineSomeMoreBusinessAsLinqTest()
// {
// Func<IQueryable<MyItem>, IQueryable<string>> inputAccounts = q => Enumerable.Repeat("hello", 1).AsQueryable();
// var business = inputAccounts.DefineSomeMoreBusinessAsLinq();
// var result = business(null).ToList().First();
// Assert.AreEqual("External hello", result);
// }
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment