2012-02-05 12 views
5

Po prostu mały pomysł, z którym gram, nie jestem pewien, czy jest to wykonalne lub ma wiele zastosowań.Tworzenie kodu EF Pierwszego kontekstu DbContext za pomocą Roslyn

Próbuję wygenerować bardzo prosty kod EF Pierwszą bazę danych za pomocą Roslyn CTP.

Kod:

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(); 

Po uruchomieniu pojawia się następujący wyjątek

Wyjątek:

typu 'Składanie # 0 + Car' nie został odwzorowany. Sprawdź, czy typ nie został jawnie wykluczony przy użyciu metody Ignoruj ​​lub NotMappedAttribute adnotacji danych. Sprawdź, czy typ został zdefiniowany jako klasa, nie jest pierwotny, zagnieżdżony lub ogólny i nie dziedziczy po EntityObject.

Przeglądając listę możliwych problemów, domyślam się, że Roslyn tworzy klasę zagnieżdżoną jako część kodu genowego. To ma sens inaczej "nowy kontekst();" wywołanie musiałoby być zawinięte do jakiejś klasy/metody. Mógłbym wyemitować zespół, który potwierdziłby powyższe, ale prawdopodobnie nie miałby żadnych wskazówek, jak poprawnie napisać.

Przeszedłem również na ścieżkę Syntax.ClassDeclaration, ale skończyłem z kilkoma setkami linii kodu, aby utworzyć klasę z jedną właściwością i nie było żadnego oczywistego sposobu na utworzenie instancji tej klasy.

Pytanie

Czy istnieje prosty sposób utworzyć klasę w Roslyn, który jest publicznie dostępny (na przykład nie zagnieżdżona w innej klasie)?

Odpowiedz

5

Można użyć Roslyn stworzyć rzeczywistą bibliotekę DLL, który zawiera typ na podstawie kodu źródłowego, a następnie użyć tego ze skryptu:

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

potrzebowała lekkiej modyfikacji, przekazując pełną ścieżkę EF do skryptu engine - typeof (DbContext) .Assembly.Location. W przeciwnym razie działa idealnie. – Betty

+0

znasz sposób ładowania utworzonego zestawu do skryptu skryptowego bez zapisywania go na dysku? ScriptEngine wydaje się generować wyjątek "Path is not be empty", jeśli przekażę zestaw utworzony przez metodę memorystream -> bytes -> assembly. – Betty

+2

Tak, wydaje się, że to niemożliwe. Próbowałem go z dynamicznym montażem, i to też nie działało. – svick

Powiązane problemy