存储库模式和组合/连接实体作为优化的SQL

时间:2015-07-25 06:22:08

标签: c# design-patterns repository-pattern

我正在建立一个系统之上的存储库系统,这个系统比平常更难处理(参考previous question by me)。

反正。

我的数据模型在这一点上相当简单:我有几个国家,每个国家都有0个或更多机场。这是我的基础知识库:

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];
    }
}

请忽略丑陋的GetById()实施;我在Unity3D的(Mono的).NET库上运行它,并且在那里看似a bug,这使得目前无法正确地执行它。无论哪种方式,这不是问题。 :)

现在,正常的EntityRepository看起来像这样(在本例中为CountryRepository):

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 );
    }
}

国家/地区实体如下所示:

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

然后,在我的应用程序中,我可以做这样的事情:

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

......这很好用;我很高兴一切都被抽象出来等等。)

问题是上述代码为每个国家/地区创建一个数据库SELECT,这是非常无效的。这是我不知道在哪里前进的地方。我知道如何使用普通的旧SQL执行此操作,但我想使用Linq(或其他“非SQL”)方式。

有人能指出我正确/正确的方向吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

我在SimpleSQL的文档中看不到任何东西,看起来它会让sql lite生成一个连接 - 类似于实体框架的Include方法。

也就是说,您可以通过2个查询将所有机场和国家带入内存并手动将它们相互挂钩,如下所示:

var airports = RepositoryFactory.AirportRepository.GetAll().ToList();
var countries = RepositoryFactory.CountryRepository.GetAll().ToList();
countries.ForEach(c => c.Airports = airports.Where(a => a.CountryId == c.Id));

请注意,您需要向国家/地区类添加属性:

public IEnumerable<Airport> Airports {get;set;}

我不喜欢它,但这可能是给你环境的唯一方式。您可以使用泛型进一步抽象连接/映射逻辑,但这是基本思想。