【问题标题】:Initialize DbSet from query?从查询初始化 DbSet?
【发布时间】:2015-10-06 08:43:19
【问题描述】:

我试图弄清楚如何让我的 DbSet 初始化来自自定义查询。

说明:

我的 DbSet 将是只读的。

假设我的数据库中有 3 个表。我编写了一个 SQL 查询,对 3 个表进行了复杂的选择。现在我想使用实体框架来查询查询的结果。

我认为这可以通过创建这样的东西来实现:

class MyCustomContext : DbContext
{
    public MyCustomContext(string connectionString) 
        : base(connectionString)
    {

    }

    public DbSet<MyQueryResultRow> ResultsRows { get; set; }
}

但我不知道如何对 DbContext 说“嘿,要检索该 DbSet 的行,请使用该 sql 查询!”。

注意:我不能也不想修改数据库(例如我不能创建 sql 视图)。

有什么想法吗?

【问题讨论】:

  • 它似乎没有回答我的问题。我真的很想使用实体框架数据集,因为我需要做一些 OrderBy / Take / Skip 等,我希望实体框架在数据库端执行此操作。我不想获取所有数据然后在上面创建 Linq。
  • 为什么不能在上下文中添加 3 个 DbSet 属性(每个表一个)并将它们与 Linq 连接起来?
  • DbSet 不是数据集 - 它允许您查询实体。结果放在 DbSet 中,它们只是对象。您也不需要它来执行查询。你想让我做什么?您要执行什么类型的查询?
  • @Floc 你怎么知道的?例如,左连接只是一个 1:N 关系。子查询通常只是另一个.Select().Where() 组合(尽管性能可能很糟糕)。 请发布查询

标签: c# entity-framework dbcontext


【解决方案1】:

您可以像往常一样创建 dbContext,然后将 SqlQuery 用于“非实体”类型。

例如:

using (var context = new myDbContext()) 
{ 
    var things = context.Database.SqlQuery<myType>( 
                       "SELECT things FROM dbo.myTables").ToList(); 
}

关键是使用context.Database 然后您可以访问所有表(当然,您的 SQL 帐户也可以访问!),您可以定义您的“myType”来映射您选择的列。

【讨论】:

  • 这应该是最后的手段——如果查询很复杂,维护一个硬编码的 SQL 字符串会很困难。创建适当的映射和关系要好得多。对于复杂的查询,视图会更好
  • 确实如此,但正如他所说——“我不能也不想修改数据库(例如,我不能创建 sql 视图)。”
  • 最后,我使用了这个答案。我返回 context.Database.SqlQuery("query") 然后我对其执行一些 Take / Skip / OrderBy ,然后执行查询。这不是最好的方法,但它确实有效。
【解决方案2】:

创建一个代表 1 对 1 的类,该类将由 SQL 返回。

这包括数据类型。

public class CustomClass
{
    public int Id {get; set;}
    public string Name {get; set;}
    ....
}

//you  can pass in variables to this method...
public List<CustomClass> GetCustomeClass()
{
    //here you just need to ensure what you select matches the class(CustomClass).
    string query = "Select * from Table_XYS";

    List<CustomClass> res = context.Database.SqlQuery<CustomClass>(query).ToList();

    return res;

}

假设 Table_XYS 有两个字段,Id(int) 和 Name(nvarchar),那么这将按原样工作。

这里的要点是 SQL 查询可以包括连接或分组,或者只要自定义类和 SQL 中的最终选择具有相同的属性/字段......包括类型。然后它将为您绑定数据。

【讨论】:

  • 是的,我知道该解决方案,但我需要对查询结果使用 Linq to Entities。使用该解决方案,我只能使用标准 Linq。这不是我想要的。
  • 是的,您可以...只需在 SQL 中对其进行过滤...将其作为基础并将其作为 IQueriable 返回...或者更好地在 Linq 中将整个内容从 DBset 中写入...跨度>
【解决方案3】:

也许您可以尝试添加另一个图层,例如存储层:

public class MyCustomRepository
{
    private readonly MyCustomContext _context;
    public MyCustomRepository(MyCustomContext context)
    {
        _context = context;
    }

    public IEnumerable<MyQueryResultRow> GetResultRows()
    {
        return _context.ResultsRows.Where(r => r.Id > 10); // Here you can add some restrictions
    }
}

返回 IEnumerable 不会执行查询。只有在执行 .ToList() 方法后,查询才会在数据库中执行,因此您可以轻松添加更多子句:

var myExtendedQueryResults = repository
    .GetResultRows()
    .Skip(5)
    .OrderBy(r => r.Name)
    .Take(10)
    .ToList();

【讨论】:

  • 你理解OP的问题错了,他甚至没有ResultsRows的属性按照他想要的方式设置。正如他所说,他想要一个从一些自定义 SQL 查询构建的查询。正如其他答案建议使用context.Database.SqlQuery&lt;&gt;(...)
  • 编辑:读得太快了。这就是我想要的,但在我需要在不获取所有记录的情况下检索“ResultsRows”之前。
  • @Floc 根据您的要求,它不是您可以使用的解决方案。除非您以其他方式解决您的 original 问题(而不是尝试从自定义 sql 查询构建 DbSet)。
  • 一个 ORM 存储库的组件之一。并返回 IEnumerable 执行查询 - 您必须返回 IQueryable 以避免执行。事实上,这个答案与 LINQ to Entities 已经做的并没有什么不同(除了意外加载数据)
  • @PanagiotisKanavos 我不认为你在这里说的是真的。有人会读到这个并记住你写的东西。 IEnumerable 不执行查询。例如看到这个:stackoverflow.com/questions/4061951/…这并不意味着我的回答在问题的范围内是正确的,我承认我没有完全理解它:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-07
相关资源
最近更新 更多