5

Ich habe eine ASP.NET MVC-Anwendung, die Entity Framework verwendet, um Daten abzurufen.Wie können Projektionen im Entity Framework wiederverwendet werden?

Ich muss Entitäten zu Modellen transformieren, bevor Sie sie an Ansicht übergeben. Die Vorsprünge können sehr komplex sein, aber es einfach zu halten:

public static IQueryable<UserModel> ToModel(this IQueryable<User> users) 
{ 
    return from user in users 
      select new UserModel 
      { 
       Name = user.Name, 
       Email = user.Email, 
      }; 
} 

Dies kann in einem Controller wie folgt verwendet werden:

return View(Repository.Users.ToModel().ToList()); 

Sehr gut. Aber was, wenn ich diese Projektion in einem anderen verwenden möchte? Beispiel:

public static IQueryable<BlogPostModel> ToModel(this IQueryable<BlogPost> blogs) 
{ 
    return from blogs in blogs 
      select new BlogPostModel 
      { 
       Title = blog.Title, 
       Authors = blog.Authors.AsQueryable().ToModel(), // (entities are POCOs) 
       // This does not work, because EF does not understand method ToModel(). 
      }; 
} 

(nehmen wir an, Blog kann mehr als einen Autor haben und es ist vom Typ Benutzer).

Kann ich die Projektionen irgendwie trennen und in anderen wiederverwenden?

+1

Siehe http: // stackoverflow.com/a/11679134/861716. –

Antwort

8

Hier ist etwas, das tatsächlich funktioniert (in einer einfachen Testanwendung) nur wählen die gewünschten Felder:

namespace Entities 
{ 
    public class BlogPost 
    { 
     public virtual int Id { get; set; } 
     public virtual string Title { get; set; } 
     public virtual DateTime Created { get; set; } 
     public virtual ICollection<User> Authors { get; set; } 
    } 

    public class User 
    { 
     public virtual int Id { get; set; } 
     public virtual string Name { get; set; } 
     public virtual string Email { get; set; } 
     public virtual byte[] Password { get; set; } 
     public virtual ICollection<BlogPost> BlogPosts { get; set; } 
    } 
} 

namespace Models 
{ 
    public class BlogPostModel 
    { 
     public string Title { get; set; } 
     public IEnumerable<UserModel> Authors { get; set; } 
    } 

    public class UserModel 
    { 
     public string Name { get; set; } 
     public string Email { get; set; } 
    } 

    public static class BlogPostModelExtensions 
    { 
     public static readonly Expression<Func<BlogPost, BlogPostModel>> ToModelConverterExpression = 
      p => 
      new BlogPostModel 
      { 
       Title = p.Title, 
       Authors = p.Authors.AsQueryable().Select(UserModelExtensions.ToModelConverterExpression), 
      }; 

     public static readonly Func<BlogPost, BlogPostModel> ToModelConverterFunction = ToModelConverterExpression.Compile(); 

     public static IQueryable<BlogPostModel> ToModel(this IQueryable<BlogPost> blogPosts) 
     { 
      return blogPosts.Select(ToModelConverterExpression); 
     } 

     public static IEnumerable<BlogPostModel> ToModel(this IEnumerable<BlogPost> blogPosts) 
     { 
      return blogPosts.Select(ToModelConverterFunction); 
     } 
    } 

    public static class UserModelExtensions 
    { 
     public static readonly Expression<Func<User, UserModel>> ToModelConverterExpression = 
      u => 
      new UserModel 
      { 
       Name = u.Name, 
       Email = u.Email, 
      }; 

     public static readonly Func<User, UserModel> ToModelConverterFunction = ToModelConverterExpression.Compile(); 

     public static IQueryable<UserModel> ToModel(this IQueryable<User> users) 
     { 
      return users.Select(ToModelConverterExpression); 
     } 

     public static IEnumerable<UserModel> ToModel(this IEnumerable<User> users) 
     { 
      return users.Select(ToModelConverterFunction); 
     } 
    } 
} 

es zu testen, ohne tatsächlich eine Datenbank zu erstellen:

var blogPostsQuery = (
    from p in context.BlogPosts 
    where p.Title.StartsWith("a") 
    select p).ToModel(); 
Console.WriteLine(((ObjectQuery)blogPostQuery).ToTraceString()); 
+3

Gute Idee! Aber ich denke, es ist keine "verschachtelte" Projektion, die in der Datenbank passiert. Es lädt die vollständigen "Autor" -Entitäten und projiziert dann in den Setter im Speicher, d. H. Wirft einige oder vielleicht viele der geladenen Spalten/Eigenschaften weg. – Slauma

+0

@Slauma Oh, du hast Recht, das habe ich vermisst. Ich werde darüber nachdenken. – hvd

+0

Das kompiliert und läuft korrekt, aber @Slauma ist richtig .. Ich habe den Profiler überprüft und es ruft den gesamten Benutzer aus der DB. Was denkst du, ist es lösbar? Vielen Dank! – jakubka

Verwandte Themen