vendredi 24 juillet 2015

Repository pattern and combined/joined entities as optimised SQL

I'm working on building a repository system on top of a system that is a bit harder to work on than usual (ref. a previous question by me).

Anyway.

My data model is fairly simple at this point: I have several countries, and each country has 0 or more airports. Here's my base Repository:

public abstract class Repository<T> : IRepository<T> where T : Entity, new()
{
    protected SimpleSQLManager SQLManager = DatabaseManager.Instance.SQLManager;

    public virtual IQueryable<T> GetAll()
    {
        IQueryable<T> all = SQLManager.Table<T>().AsQueryable();

        return all;
    }

    public virtual IQueryable<T> GetAll(Expression<Func<T, bool>> predicate)
    {
        IQueryable<T> all = SQLManager.Table<T>().Where(predicate).AsQueryable();

        return all;
    }

    public T GetById(string tableName, int id)
    {
        return SQLManager.Query<T>( "SELECT * FROM " + tableName + " WHERE Id = ?", id )[0];
    }
}

Please ignore the ugly GetById() implementation; I'm running this on Unity3D's (Mono's) .NET libraries, and there's seemingly a bug in there which makes it impossible at the moment to do it properly. Either way, that's not the problem. :)

Now, a normal EntityRepository looks like this (CountryRepository in this case):

public class CountryRepository : Repository<Country>
{
    public override IQueryable<Country> GetAll()
    {
        return base.GetAll().OrderBy( c => c.Name );
    }

    public Country GetById(int id)
    {
        return base.GetById( "Country", id );
    }
}

The Country entity looks like this:

public class Country : Entity
{
    public IQueryable<Airport> Airports()
    {
        return RepositoryFactory.AirportRepository.GetByCountry( this );
    }
}

Then, in my application I can do something like this:

foreach ( Country c in RepositoryFactory.CountryRepository.GetAll() )
{
    foreach ( Airport a in c.Airports() )
    {
        // ...
    }
}

...and this works just fine; I'm happy with how everything is abstracted away etc. etc. :)

The problem is that the above code creates one database SELECT per country, which is highly ineffective. This is where I'm not sure where to go forward. I know how to do this with plain old SQL, but I want to go the Linq (or otherwise "non-SQL") way.

Can someone point me in the right/correct direction?

Thanks!

Aucun commentaire:

Enregistrer un commentaire