5

我一直在使用带有 POCO First 方法的实体框架。我几乎遵循了 Steve Sanderson 在他的“Pro ASP.NET MVC 3 Framework”一书中描述的模式,使用 DI 容器和 DbContext 类连接到 SQL Server。

SQL Server 中的基础表包含不同应用程序使用的非常大的数据集。因此,我不得不为我的应用程序中需要的实体创建视图:

class RemoteServerContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<Contact> Contacts { get; set; }
    ...

    protected override void  OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>().ToTable("vw_Customers");
        modelBuilder.Entity<Order>().ToTable("vw_Orders");
        ...
    }
}

这似乎可以满足我的大部分需求。

我遇到的问题是,其中一些视图中有大量数据,因此当我调用类似以下内容时:

var customers = _repository.Customers().Where(c => c.Location == location).Where(...);

它似乎正在带回整个数据集,这可能需要一些时间才能使 LINQ 查询将数据集减少到我需要的数据集。当标准仅适用于少数记录并且我从 SQL 服务器获取整个数据集时,这似乎非常低效。

我试图通过使用存储过程来解决这个问题,例如

public IEnumerable<Customer> CustomersThatMatchACriteria(string criteria1, string criteria2, ...) //or an object passed in!
{
    return Database.SqlQuery<Customer>("Exec pp_GetCustomersForCriteria @crit1 = {0}, @crit2 = {1}...", criteria1, criteria2,...);
}

虽然这要快得多,但这里的问题是它不返回 DbSet,因此我失去了我的对象之间的所有连接,例如,即使我包含它们的 ID,我也无法引用任何关联的对象,例如订单或联系人因为返回类型是“客户”的集合,而不是它们的 DbSet。

有没有人有更好的方法让 SQL Server 进行查询,这样我就不会传递大量未使用的数据?

4

4 回答 4

4
var customers = _repository.Customers().Where(c => c.Location == location).Where(...

如果Customers()返回IQueryable,则仅此语句实际上根本不会“带回”任何内容-调用WhereanIQueryable会给您另一个IQueryable,并且直到您执行导致查询执行的某些操作(例如ToList,或FirstOrDefault),才会真正执行任何操作并且结果返回。

但是,如果此Customers方法返回实例化对象的集合,那么是的,因为您要求所有对象都得到它们。

我从来没有使用过代码优先或什至存储库模式,所以我不知道该建议什么,除了IQueryable尽可能长时间地停留在领域,并且只有在你应用了所有之后才执行查询相关过滤器。

于 2012-05-15T08:48:08.033 回答
2

如果只返回一组数据,我会采取以下措施:

var customers = (from x in Repository.Customers where <boolean statement> &&/|| <boolean statement select new {variableName = x.Name , ...).Take(<integer amount for amount of records you need>);

例如:

var customers = (from x in _repository.Customers where x.ID == id select new {variableName = x.Name} ).take(1000);

然后遍历结果以获取数据:(请记住,linq 语句返回一个 IQueryable)...

foreach (var data in customers)
{
   string doSomething = data.variableName; //to get data from your query.
}

希望这会有所帮助,不完全相同的方法,但我发现这在我的代码中很方便

于 2012-05-15T09:00:59.197 回答
1

可能是因为您的存储库中的 Cusomters() 方法正在执行 GetAll() 类型的事情并首先获取整个列表。这会禁止 LINQ 和您的 SQL Server 创建智能查询。

我不知道您的存储库是否有一个好的解决方法,但如果您愿意这样做:

using(var db = new RemoteServerContext())
{
  var custs = db.Customers.Where(...);
}

我认为这会快很多。如果您的项目足够小,则无需存储库即可。当然,你会失去一个抽象层,但对于小型项目,这可能不是一个大问题。

另一方面,您可以一次将所有客户加载到您的存储库中并直接使用生成的集合(而不是填充列表的方法调用)。但要小心添加、删除和修改客户。

于 2012-05-15T09:05:14.450 回答
0

您需要 LINQ 查询返回较少的数据,例如 sql 分页,如 sqltop中的函数或使用存储过程进行手动查询。无论哪种情况,您都需要重写查询机制。这也是我没有使用 EF 的原因之一,因为你对看起来的代码没有太多的控制权。

于 2012-05-15T08:41:15.543 回答