¿Cómo simplifico el acceso de una relación has-many con el marco de la entidad?

c# entity-framework entity-framework-core

Pregunta

Esto es lo que quiero hacer:

var user = db.User.First(conditions);
user.Book.First();

Aquí está actualmente cómo tengo que hacer eso.

var user = db.User.First(conditions);
user.Book.First();

La razón por la que quiero simplificar esto es porque no quiero tener que especificar qué se incluye cada vez que quiero acceder a una relación. Parece muy engorroso.

por ejemplo: me gustaría poder hacer lo siguiente, dado que anteriormente he recuperado un usuario:

var user = db.User.First(conditions);
user.Book.First();

Aquí está lo que tengo hasta ahora:

var user = db.User.First(conditions);
user.Book.First();

Y luego, cómo se usaría eso sería lo siguiente:

var user = db.User.First(conditions);
user.Book.First();

Tengo alguna otra lógica en mi código que abstrae eso que me permitiría hacer user.Book.First() . Ojalá pueda obtener permiso para abrir mucho de esto, ya que estoy modelando una gran cantidad de API después de un desorden al estilo ActiveRecord.

Tenga en cuenta que estoy usando un conjunto de extensiones que hice para ayudar a lidiar con la dinamismo menos doloroso: https://github.com/NullVoxPopuli/csharp-extensions

ACTUALIZACIÓN 1:

var user = db.User.First(conditions);
user.Book.First();

Por ahora, he codificado el reparto del usuario en un intento de que algo funcione. Mi error ahora es:

var user = db.User.First(conditions);
user.Book.First();

Respuesta popular

Este no es un problema trivial, y no hay un enfoque de "talla única". Lo que realmente parece estar buscando es la carga lenta, que no se incluyó en EF7 por muchas razones .

No sé qué se supone que debe hacer el código que muestra, pero una opción sería introducir un patrón de repositorio, donde se especifican las "entidades a incluir" en el nivel de colección:

public class UserRepository
{
    private readonly IQueryable<User> _dataSet;

    public UserRepository(IQueryable<User> userDataSet)
    {
        _dataSet = userDataSet;
    }

    public IQueryable<User> Include()
    {
        return _dataSet.Include(u => u.Book)
                       .Include(u => u.Blog);
    }
}

Y puede mover gran parte de la lógica a una clase base genérica, dejándolo solo con el método Include() . Por ejemplo, puede trabajar con cadenas como muestra (o enumeraciones, o ...), para seleccionar solo las entidades relacionadas para incluir:

public class UserRepository
{
    private readonly IQueryable<User> _dataSet;

    public UserRepository(IQueryable<User> userDataSet)
    {
        _dataSet = userDataSet;
    }

    public IQueryable<User> Include()
    {
        return _dataSet.Include(u => u.Book)
                       .Include(u => u.Blog);
    }
}

Y luego en UserRepository :

public class UserRepository
{
    private readonly IQueryable<User> _dataSet;

    public UserRepository(IQueryable<User> userDataSet)
    {
        _dataSet = userDataSet;
    }

    public IQueryable<User> Include()
    {
        return _dataSet.Include(u => u.Book)
                       .Include(u => u.Blog);
    }
}

Y luego úsalo así:

public class UserRepository
{
    private readonly IQueryable<User> _dataSet;

    public UserRepository(IQueryable<User> userDataSet)
    {
        _dataSet = userDataSet;
    }

    public IQueryable<User> Include()
    {
        return _dataSet.Include(u => u.Book)
                       .Include(u => u.Blog);
    }
}

Una alternativa sería incluir siempre todas las propiedades de navegación (recursivamente), pero ese sería un enfoque horrible en términos de eficiencia de consulta, ya que cada consulta será una combinación masiva de todas las tablas relacionadas, sea necesario o no.




Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué