Pregunta

Actualmente estoy creación de un nuevo proyecto, y me he encontrado con algunas cosas, en las que necesito un poco de entrada.

Esto es lo que estoy considerando:

  • Me gustaría un repositorio genérico

  • No quiero volver IQueryable de mi repositorio.

  • Me gustaría encapsular mis consultas en las especificaciones.

  • he implementado el patrón especificación

  • Tiene que ser fácilmente comprobable

Ahora es cuando me pongo un poco atascado y mi pregunta es de qué manera sería la forma más elegante de llamar al método de búsqueda con una o más especificaciones:

(Fluido): bannerRepository.Find().IsAvailableForFrontend().IsSmallMediaBanner()

o expresar consultas como lambdas con mis especificaciones

(Lambda): bannerRepository.Find.Where(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner)

o tal vez alguna otra manera por completo? Lo más importante es que el chico la aplicación de la parte delantera MVC, debe tener una buena experiencia intuitiva del repositorio.

Lo que yo soy la esperanza de lograr es mantener la flexibilidad som con respecto a ser capaz de combinar las especificaciones, y dar a la experiencia de "filtrado" con los Specfications, pero sin fugas IQueryable al controlador, sino más bien como un ISpecifiable, que sólo permite modificar la consulta con las especificaciones y no con LINQ. Pero solo estoy de vuelta en fugas lógica de consulta al controlador de esta manera?

¿Fue útil?

Solución

He visto algunos de Fluent API que utiliza las propiedades de las especificaciones, por lo que no añada el ruido paréntesis para los clientes.

bannerRepository.Find.IsAvailableForFrontend.IsSmallMediaBanner.Exec()

Siendo Exec () un método para ejecutar las especificaciones contra el repositorio.

Pero incluso si usted no utiliza las propiedades, me gustaría ir a la API fluida, ya que cuenta con el mínimo ruido.

Otros consejos

  

o tal vez alguna otra manera por completo?

Bueno, en realidad no entiendo exactamente su aplicación repositorio (por ejemplo, ¿cuál será el método .Find() volver?), Pero yo elegiría otra dirección:

public class Foo 
{ 
    public Int32 Seed { get; set; }
}

public interface ISpecification<T> 
{
    bool IsSatisfiedBy(T item);
}

public interface IFooSpecification : ISpecification<Foo> 
{
    T Accept<T>(IFooSpecificationVisitor<T> visitor);
}

public class SeedGreaterThanSpecification : IFooSpecification
{
    public SeedGreaterThanSpecification(int threshold)
    {
        this.Threshold = threshold;
    }
    public Int32 Threshold { get; private set; }
    public bool IsSatisfiedBy(Foo item) 
    {
        return item.Seed > this.Threshold ;
    }
    public T Accept<T>(IFooSpecificationVisitor<T> visitor)
    {
        return visitor.Visit(this);
    }
}
public interface IFooSpecificationVisitor<T>
{
    T Visit(SeedGreaterThanSpecification acceptor);
    T Visit(SomeOtherKindOfSpecification acceptor);
    ...
}
public interface IFooRepository 
{
    IEnumerable<Foo> Select(IFooSpecification specification);
}
public interface ISqlFooSpecificationVisitor : IFooSpecificationVisitor<String> { }
public class SqlFooSpecificationVisitor : ISqlFooSpecificationVisitor
{
    public string Visit(SeedGreaterThanSpecification acceptor)
    {
        return "Seed > " + acceptor.Threshold.ToString();
    }
    ...
}
public class FooRepository
{   
    private ISqlFooSpecificationVisitor visitor;

    public FooRepository(ISqlFooSpecificationVisitor visitor)
    {
        this.visitor = visitor;
    }

    public IEnumerable<Foo> Select(IFooSpecification specification)
    {
        string sql = "SELECT * FROM Foo WHERE " + specification.Accept(this.visitor);
        return this.DoSelect(sql);
    }

    private IEnumerable<Foo> DoSelect(string sql)
    {
        //perform the actual selection;
    }
}

Así que tengo una entidad, su interfaz especificación y varios implementadores implicados en un patrón de visitante, su interfaz de repositorio de aceptar una especificación de interfaz y su aplicación repositorio, aceptando un visitante capaces de traducir las especificaciones en las cláusulas SQL (pero es sólo una cuestión de este caso, por supuesto). Por último, me componer especificación de la interfaz de repositorio "fuera" (usando la interfaz de fluido).

Tal vez esto es sólo una idea ingenua, pero me resulta bastante sencillo. Espero que esto ayude.

En lo personal me gustaría ir con la forma de lambda. Puede ser debido a mi amor por lambda sino que proporciona gran cantidad de espacio para una configuración de repositorio genérico.

Teniendo en cuenta lo siguiente:

bannerRepository.Find.Where(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner)

No sé lo que su patrón se parece pero se puede refactorizar algunas cosas aquí:

Crea una interfaz genérica llamada 'IRepository' de tipo que contiene todos los métodos de acceso de datos.

Se podría tener este aspecto:

interface IRepository<T> where T : class
{
    IEnumerable<T> FindAll(Func<T, bool> exp);

    T FindSingle(Func<T, bool> exp);
}   

Crea una clase abstracta 'depósito' la implementación de esta interfaz:

class Repository<T> : IRepository<T> where T : class
{
    TestDataContext _dataContext = TestDataContext();

    public IEnumerable<T> FindAll(Func<T, bool> exp)
    {
        _dataContext.GetTable<T>().Where<T>(exp);
    }

    public T FindSingle(Func<T, bool> exp)
    {
        _dataContext.GetTable<T>().Single(exp);
    }
}

Ahora podemos crear una interfaz para la mesa / objetos banderas que implementa nuestra 'IRepository' y una clase concreta que se extiende la clase abstracta 'depósito' y la aplicación de la 'IBannerInterface':

interface IBannerRepository : IRepository<Banner>
{
}

Y el repositorio de juego para ponerlo en práctica:

class BannerRepository : Repository<Banner>, IBannerRepository
{
}

Se recomienda usar este enfoque, ya que le da una gran flexibilidad, así como el poder suficiente para controlar todas las pequeñas entidades que tiene.

Llamar a esos métodos será muy fácil de esa manera:

BannerRepository _repo = new BannerRepository();

_repo.FindSingle(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner);

Sí, esto significa que usted tiene que hacer algo de trabajo, pero es el infierno más fácil para usted para cambiar la fuente de datos más adelante.

Espero que ayude!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top