Proyección de entidades únicas en EF con métodos de extensión.

c# entity-framework expression-trees

Pregunta

Me gusta hacer la proyección de los modelos de mi entidad en mis modelos de vista utilizando métodos de extensión. Esto significa que no estoy por encima o por debajo de mis modelos y hace que el código sea agradable y legible. Tiene sentido que a veces las proyecciones pueden incluir modelos anidados, y quiero reutilizarme en esas subproyectos.

Quiero poder hacer algo como lo siguiente:

ctx.People.FiltersAndThings().ToViewModels();//the project my DB Models into view models

Métodos de extensión para la proyección real.

public static IQueryable<PersonModel> ToViewModels(this IQueryable<Person> entities)
{
    return entities.Select(x => new PersonModel {
        Me = x.Me.ToViewModel(), //this method cannot be translated into a store expression
        Friends = x.Friends.AsQueryable().ToViewModels() //works fine with some magic (tm)
    });
}

public static IQueryable<ProfileModel> ToViewModels(this IQueryable<Profile> entities)
{
    return entities.Select(x => new ProfileModel { Name = x.Name });
}


public static ProfileModel ToViewModel(this Profile entity)
{
    return new ProfileModel { Name = entity.Name };
}

Cuando usamos un Queryable (por ejemplo, Friends = x.Friends.AsQueryable().ToViewModels() ) podemos usar algo de magia para aplanar esto en una expresión (consulte https://stackoverflow.com/a/10726256/1070291 , responda con @ LordTerabyte) Pero cuando estamos haciendo una asignación con una nueva cláusula (por ejemplo, Me = new ProfileModel { Name = x.Me.Name } ) no es una expresión, por lo tanto, si incluimos esto bajo un método de extensión (por ejemplo, Me = x.Me.ToViewModel() ) no podemos aplanar esto a una expresión.

¿Cómo funciona una asignación a un nuevo objeto bajo las escenas en EF?

¿Hay una manera de hacer la conversión a un nuevo objeto a través de un método de extensión?

Código de demostración completo aquí: https://github.com/lukemcgregor/ExtensionMethodProjection

Editar:

Ahora tengo una publicación de blog ( Repositorios compactables - Extensiones de anidación ) y un paquete nuget para ayudar con los métodos de extensión de anidación en linq

Respuesta aceptada

Echa un vistazo a esta respuesta . Hace una cosa muy similar a lo que quieres. Básicamente, definirías tu transformación como un árbol de Expresión, por ejemplo:

public static Expression<Func<Profile, ProfileModel>> ToProfileViewModel()
{
    return entity => new ProfileModel { Name = entity.Name };
}

Y luego haga invocaciones de esto (por ejemplo, ExpressionsHelper.ToProfileViewModel (). AsQuote () (p)).

Si lo prefiere, puede modificar los visitantes, para permitir una sintaxis más agradable. Algo a lo largo de las líneas:

[ReplacementInExpressionTrees(MethodName=nameof(ExpressionsHelper.ToProfileViewModel))]
public static ProfileModel ToViewModel(this Profile profile)
{
    // this implementation is only here, so that if you call the method in a non expression tree, it will still work
    return ExpressionsHelper.ToProfileViewModel().Compile()(profile); // tip: cache the compiled func!

Ahora necesita crear un visitante, que verifique todas las llamadas de método, y cuando encuentra un método con este atributo, cambia la llamada completa a ExpressionsHelper.ToProfileViewModel (). AsQuote () (perfil). Esto es como un ejercicio para ti :)}



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow