使用实体框架提高效率

时间:2012-05-15 08:31:16

标签: c# .net entity-framework

我一直在使用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,因为返回类型是'Customers'的集合而不是它们的DbSet。

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

4 个答案:

答案 0 :(得分:4)

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

如果Customers()返回IQueryable,则此声明实际上根本不会“撤回”任何内容 - 在Where上调用IQueryable会为您提供另一个IQueryable ToList 1}},直到你做一些导致查询执行的事情(例如FirstOrDefaultCustomers),才会实际执行任何事情并返回结果。

但是,如果这个IQueryable方法返回一个实例化对象的集合,那么是的,因为你要求所有的对象都是你得到的。

我从来没有使用过代码优先或甚至是存储库模式,所以我不知道该建议什么,除了尽可能长时间地停留在{{1}}的范围内,并且只执行您应用了所有相关过滤器后的查询。

答案 1 :(得分: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.
}

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

答案 2 :(得分:1)

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

我不知道您的存储库是否有一个很好的解决方法,但是如果您要执行以下操作:

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

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

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

答案 3 :(得分:0)

您需要LINQ查询在sql中返回较少的数据,如sql分页,如top函数,或者使用存储过程进行手动查询。在任何一种情况下,您都需要重写查询机制。这是我没有使用EF的原因之一,因为您似乎没有对代码进行大量控制。