Created
February 19, 2013 19:28
-
-
Save Thorium/4989024 to your computer and use it in GitHub Desktop.
Example of state of the art C#: EntityFramework done right... :-)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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