通过存储库限制对数据库的操作

时间:2014-05-13 16:34:41

标签: c# linq entity-framework repository-pattern

我已使用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();

有关如何改善这种情况或其他意见的任何建议都需要。

1 个答案:

答案 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查询,请考虑创建一个视图,以便您可以像处理任何其他表一样处理数据。