2012-02-05 78 views
5

只是一個小小的想法,我在玩,不知道它是可行的還是有很多的用處。使用Roslyn創建一個EF CodeFirst DbContext

我想使用Roslyn CTP生成一個非常基本的EF代碼優先數據庫。

代碼:

var scriptEngine = new ScriptEngine(new[] { "System", "System.Core", typeof(DbContext).Assembly.Location }); 
var session = Roslyn.Scripting.Session.Create(); 

var t = scriptEngine.CompileSubmission<DbContext>(@" 
    using System.Data.Entity;   
    public class Car { 
    public int Id {get; set;} 
    public string Name {get; set; } 
    } 

    public class Context : DbContext { 
    public DbSet<Car> Cars {get; set; } 
    } 

    new Context(); 
", session); 

t.Execute(); 

執行時我得到下面的異常

例外:

類型 '提交#0 +汽車' 並沒有映射。使用Ignore方法或NotMappedAttribute數據註釋檢查類型是否未被明確排除。驗證類型是否定義爲一個類,不是原始的,嵌套的或通用的,並且不從EntityObject繼承。

通過查看可能出現的問題列表,我猜測Roslyn正在將一個嵌套類作爲代碼gen的一部分。這是有道理的,否則「新的上下文();」調用需要被包裝成某種類/類的方法。我可以發出一個程序集,它可以確認上述內容,但可能不會有任何有關如何正確編寫它的線索。

我也沿着Syntax.ClassDeclaration的路線走了,但結束了幾百行代碼只是爲了創建一個具有1屬性的類,並且沒有明顯的方式來實例化該類。

問題

有一種簡單的方法來創建Roslyn的一類就是公開訪問(例如,不嵌套在另一個類)?

回答

5

您可以使用羅斯林創建實際的DLL庫,包含了基於源代碼的類型,然後使用從您的腳本:

var classCode = @" 
using System.Data.Entity; 

public class Car { 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class Context : DbContext { 
    public DbSet<Car> Cars { get; set; } 
}"; 

var syntaxTree = SyntaxTree.ParseCompilationUnit(classCode); 

var compilation = Compilation.Create(
    "car", 
    new CompilationOptions(assemblyKind: AssemblyKind.DynamicallyLinkedLibrary)) 
    .AddReferences(
     new AssemblyFileReference(typeof(object).Assembly.Location), // mscorlib 
     new AssemblyFileReference(typeof(Uri).Assembly.Location), // System 
     new AssemblyFileReference(typeof(IOrderedQueryable<>).Assembly.Location), // System.Data 
     new AssemblyFileReference(typeof(DbContext).Assembly.Location) // EntityFramework 
    ) 
    .AddSyntaxTrees(syntaxTree); 

var dllPath = "car.dll"; 
using (var stream = File.OpenWrite(dllPath)) 
{ 
    compilation.Emit(stream); 
} 

var code = @"new Context();"; 
var scriptEngine = new ScriptEngine(new[] { new FileInfo(dllPath).FullName, "EntityFramework" }); 

var context = scriptEngine.Execute<DbContext>(code); 
+0

所需稍作修改,使EF的完整路徑腳本引擎 - 類型(DbContext).Assembly.Location。否則,它完美的作品。 – Betty 2012-02-05 02:23:04

+0

知道將創建的程序集加載到scriptengine而無需將其寫入磁盤的任何方式?如果我傳遞由memorystream - > bytes - > assembly方法創建的程序集,ScriptEngine似乎會拋出「Path can not empty」異常。 – Betty 2012-02-05 04:38:17

+2

是的,這似乎是不可能的。我用動態裝配試了一下,也沒有用。 – svick 2012-02-05 11:36:52