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

本文关键字:优化 SQL 实体 连接 模式 组合 存储 | 更新日期: 2023-09-27 18:04:40

我正致力于在一个系统之上构建一个存储库系统,这个系统比通常更难操作(参考我之前的问题)。

此时我的数据模型相当简单:我有几个国家,每个国家有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库上运行这个,似乎有一个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 );
    }
}

Country实体如下所示:

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")的方式。

谁能给我指个正确的方向吗?

谢谢!

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

我在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;}

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