gpt4 book ai didi

sql - 具有存储库模式的抽象

转载 作者:搜寻专家 更新时间:2023-10-30 19:50:42 24 4
gpt4 key购买 nike

我正在构建一个应用程序(具体来说是一个 Web API),我想实现存储库模式来抽象数据访问层并为将来的更改做好准备。

我的目标是使存储库接口(interface)足够抽象,以便能够在它们之上实现所有技术,从 Native SQL Client(运行 sql 命令)到 orm,如 EF 或 dapper。

我已经阅读了一些关于存储库的文章,我的通用存储库的界面看起来像这样:

interface IRepository<T>
{
IEnumerable<T> FindAll();

IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate);

T FindById(int id);

void Add(T entity);

void Remove(T entity);
}

我希望 FindBy 方法接受 linq 表达式,因为另一个选项是让它接受 native sql,而这不会很好地与 linq to entity of EF 等技术一起工作。

问题是我还希望能够在此接口(interface)之上实现一个本地 sql 存储库,为了实现一个本地 sql 存储库,我需要运行 sql 命令 strings。在此界面中,我不接受任何作为字符串的 sql 命令,我接受 linq 表达式,并且 native sql 客户端无法处理 linq 表达式(据我所知)。

所以我的问题是,我怎样才能让这个接口(interface)与任何技术/orm/库/客户端/适配器兼容,你明白了......

谢谢,阿里克

最佳答案

Adbstracting 存储库是个好主意。我会尽力帮助你。首先,您的存储库必须独立于持久性,因此您需要删除方法 FindBy(Expression<Func<T, bool>> predicate) ,而是用某种 specification pattern 代替它:

interface IRepository<T>
{
IEnumerable<T> FindAll();
IEnumerable<T> FindBy(ISpecification<T> specification);
T FindById(int id);
void Add(T entity);
void Remove(T entity);
}

public interface ISpecification<T>
{
IEnumerable<T> Execute(DbContext context);
}

所以,现在我们有了独立的存储库。然后您可以为 linq 支持的持久性创建规范和存储库的实现,它看起来像这样:

public class LinqRepository<T> : IRepository<T>
{
private readonly DbContext _context;

public LinqRepository(DbContext context)
{
_context = context;
}

public IEnumerable<T> FindBy(ISpecification<T> specification)
{
return specification.Execute(_context);
}
//and others...
}

public class LinqSpecification<T> : ISpecification<T>
{
private readonly Expression<Func<T, bool>> _predicate;

public LinqSpecification(Expression<Func<T, bool>> predicate)
{
this._predicate = predicate;
}

public IEnumerable<T> Execute(DbContext context)
{
return context.Set<T>().Where(_predicate).ToList();
}
}

然后这样调用:

IRepository<Person> repository = new LinqRepository<Person>(dbContext);
var adults = repository.FindBy(new LinqSpecification<Person>(p => p.Age > 18));

另一方面,当你需要实现非linq存储库时,它可以是这样的:

public class SqlRepository<T> : IRepository<T>
{
private readonly DbContext _context;

public SqlRepository(DbContext context)
{
_context = context;
}

public IEnumerable<T> FindBy(ISpecification<T> specification)
{
return specification.Execute(_context);
}
}

public class SqlSpecification<T> : ISpecification<T>
{
private readonly string _query;

public SqlSpecification(string query)
{
_query = query;
}

public IEnumerable<T> Execute(DbContext context)
{
return context.ExecuteSql<T>(_query);
}
}

然后调用:

IRepository<Person> repository = new SqlRepository<Person>(dbContext);
var adults = repository.FindBy(new SqlSpecification<Person>("SELECT * FROM Persons WHERE Age > 18"));

当然,这不是理想的变体,但它取决于您的系统架构和其他组件。但它可以用作背景。

关于sql - 具有存储库模式的抽象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31901098/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com