2

我正在使用 Linq 创建 4 个对象集合:

var Restaurants = db.Places.Where(p => p.Tags.Any(t => t.Name == "Restaurant")).ToList();
var Bars = db.Places.Where(p => p.Tags.Any(t => t.Name == "Bar")).ToList();
var Pubs = db.Places.Where(p => p.Tags.Any(t => t.Name == "Pub")).ToList();
var Hotels = db.Places.Where(p => p.Tags.Any(t => t.Name == "Hotel")).ToList();

显然最好从数据库中读取一次,上面是否会在 SQL Server 2012 或 1 上打开 4 个连接和 4 个查询?

如果我改为执行以下操作,Entity Framework 是否只会从数据库中读取一次,我自己测试的最佳方法是什么?

var places = db.Places;
var Restaurants = places.Where(p => p.Tags.Any(t => t.Name == "Restaurant")).ToList();
var Bars = places.Where(p => p.Tags.Any(t => t.Name == "Bar")).ToList();
var Pubs = places.Where(p => p.Tags.Any(t => t.Name == "Pub")).ToList();
var Hotels = places.Where(p => p.Tags.Any(t => t.Name == "Hotel")).ToList();

这里的最佳实践是什么?有这方面的统计吗?

谢谢。

4

3 回答 3

3
var types = new[]{"Restaurant","Bar","Pub","Hotel"};
var places = db.Places.Include(p=>p.Tags).Where(p=>p.Tags.Any(t=>types.Contains(t.Name))).ToList();

var Restaurants = places.Where(p => p.Tags.Any(t => t.Name == "Restaurant"));
var Bars = places.Where(p => p.Tags.Any(t => t.Name == "Bar"));
var Pubs = places.Where(p => p.Tags.Any(t => t.Name == "Pub"));
var Hotels = places.Where(p => p.Tags.Any(t => t.Name == "Hotel"));

应该只产生 1 个查询。虽然,您正在使用水合标记 DbSet 填充位置,这可能会显着减慢查询速度。您可能可以创建一个稍微不同的查询来检索 Places 并存储它的类型,这样您就不必拥有一个完全水合的 Tags DbSet,但如果您认为有必要,我会将其留给您。

于 2013-06-09T05:53:49.073 回答
2

您可以欺骗 Entity Framework 将它们作为单个查询的一部分加载,如下所示:

var q = 
    from p in db.Places
    group p by 1 into g
    select new {
        Restaurants = g.Where(p => p.Tags.Any(t => t.Name == "Restaurant")),
        Bars = g.Where(p => p.Tags.Any(t => t.Name == "Bar")),
        Pubs = g.Where(p => p.Tags.Any(t => t.Name == "Pub")),
        Hotels = g.Where(p => p.Tags.Any(t => t.Name == "Hotel"))
    }
var results = q.Single();
于 2013-06-09T04:58:40.457 回答
0

Both of your codes results in four queries to DB.

In NHibernate, you can do that using future:

var Restaurants = places.Where(p => p.Tags.Any(t => t.Name == "Restaurant")).Future<Place>();
var Bars = places.Where(p => p.Tags.Any(t => t.Name == "Bar")).Future<Place>();
var Pubs = places.Where(p => p.Tags.Any(t => t.Name == "Pub")).Future<Place>();
var Hotels = places.Where(p => p.Tags.Any(t => t.Name == "Hotel")).Future<Place>();

And them NHibernate will set in four queries in one round-trip when the any of them request the result, as long as database supports it.

I don't think EF currently has similar feature, but in some cases like you've shown, you can OR the clauses:

var myPlaces = places.Where(p => p.Tags.Any(t => t.Name == "Restaurant")
    || p.Tags.Any(t => t.Name == "Bar")
    || t.Name == "Pub"
    || t.Name == "Hotel")).ToList();

Although you obviously can't get them separated by type, and will have to filter them again in memory. Whether or not this will result in a performance gain varies. If it's not sensible, I would recommend against it.

于 2013-06-09T04:51:22.490 回答