我已使用Entity Framework实现了工作单元和存储库模式。示例操作如下所示:
public T GetById(int id)
{
return _context.Set<T>().Find(id);
}
因此,如果我想带一个 id 12 和仅限StudentName列的记录。我不能使用上面的方法做到这一点,因为所有列都将被拉出,我可以使用Linq完成,如下所示:
Student get = context.Students
.Where(s => s.Id = 12)
.Select(s => new { StudentName = Name })
.SingleOrDefault();
目前,我正在从存储库返回IQueryable
,如下所示,以使上述方案有效:
public IQueryable<T> Query()
{
IQueryable<T> query = dbset;
return query;
}
无论如何都要将Repository置为null,因为我现在无法限制对数据库的操作。我必须查询如下:
Student get = _uow.Students
.Query()
.Where(s => s.Id = 12)
.Select(s => new { StudentName = Name })
.SingleOrDefault();
有关如何改善这种情况或其他意见的任何建议都需要。
答案 0 :(得分:2)
我认为你担心限制错误层的操作;存储库。假设您的存储库应该抽象出您的数据库和实体框架的细节,我认为这个级别太低,无法达到您想要的水平。
如果你有一个Repo per DB表,并且每个查询结果类型class
(直接SQL / EF或DB View),那么在这里引入另一个抽象层是没有意义的。最好在下一层执行此操作,或者处理事务边界的任何内容。
为了演示,这是一个更具体的例子:
给出学生数据库表:
TABLE Student
PK Id int
COLUMN Name string
COLUMN SecretData string
您的StudentRepo
应始终返回Student
类的实例:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string SecretData { get; set; }
}
然后,利用您的仓库的图层应处理您的交易(可能跨多个仓库/操作),并将其结果映射到域实体。您的域实体只能包含您要显示的字段。您可以为您需要的每个目的创建专门的域名。
public class DomainStudent
{
public int Id { get; private set; } // prevent attempts to change Ids on domain entities
public string Name { get; set; }
}
public class DomainStudentWithSecret
{
public int Id { get; private set; }
public string Name { get; set; }
public string SecretData { get; set; }
}
为了扩展您希望在存储库代码之外处理这种映射和事务边界的原因:这些事情最好留给可以跨多个数据库表操作的代码。通常,您需要获取两个单独的SQL查询的结果,并将结果映射到单个域实体。或者有时,如果初始查询失败,您希望回滚事务(或不执行后续SQL)。我发现最好保持Repos / DAO在单个表/视图/ sproc(数据库实体)上工作以抽象出Db引擎的细节,并让域层类处理如何理解数据的繁重工作。如果您需要具有许多JOIN的复杂SQL查询,请考虑创建一个视图,以便您可以像处理任何其他表一样处理数据。