C# 将Linq2SQL简单查询转换为CompiledQuery以提高应用程序性能
我正在编写一个Silverlight for Windows Phone(SDK 7.1)应用程序,并在Windows Phone Silverlight Toolkit的C# 将Linq2SQL简单查询转换为CompiledQuery以提高应用程序性能,c#,silverlight,windows-phone-7,linq-to-sql,compiled-query,C#,Silverlight,Windows Phone 7,Linq To Sql,Compiled Query,我正在编写一个Silverlight for Windows Phone(SDK 7.1)应用程序,并在Windows Phone Silverlight Toolkit的LongListSelector控件中显示CompactSQL DB中的数据 一旦列表长度变为150项左右,应用程序就会减慢加载数据的速度,在页面之间来回导航,并且动画无法显示(我知道使用后台线程将有助于释放UI线程用于动画) 我目前经常使用三个查询—每次LongListSelector中的数据更新或页面导航到。我已经将Mov
LongListSelector
控件中显示CompactSQL DB中的数据
一旦列表长度变为150项左右,应用程序就会减慢加载数据的速度,在页面之间来回导航,并且动画无法显示(我知道使用后台线程将有助于释放UI线程用于动画)
我目前经常使用三个查询—每次LongListSelector中的数据更新或页面导航到。我已经将MoviesByTitle
转换成了CompiledQuery
,这对我的其他两个查询(groupedMovies和LongListSelector.ItemSource
类型的List
)有很大帮助,但我似乎无法找到正确的语法
关于如何通过使用CompiledQuery
或其他方式提高这些查询的效率,有什么建议吗
MoviesByTitle
属于另一个名为querys
public static Func<MovieDBContext, IOrderedQueryable<Movies>> MoviesByTitle = CompiledQuery.Compile((MovieDBContext db) => from m in db.Movies orderby m.Title,m.Year select m);
组
类如下
public class Group<T> : IEnumerable<T>
{
public Group(string name, IEnumerable<T> items)
{
this.Title = name;
this.Items = new List<T>(items);
}
public string Title
{
get;
set;
}
public IList<T> Items
{
get;
set;
}
...
}
公共类组:IEnumerable
{
公共组(字符串名称,IEnumerable项)
{
this.Title=名称;
此项=新列表(项);
}
公共字符串标题
{
得到;
设置
}
公共物品
{
得到;
设置
}
...
}
我假设GroupHeader
是存储在数据库中的实体,与电影
实体有1-n关系
首先,我在这里没有看到3db查询。LINQ表达式并不总是DB查询(例如,存在LINQ to对象)。有时,确定到底发生了什么是相当具有挑战性的。在这种情况下,最好的朋友是DB profiler工具或IntelliTrace——它们显示在运行时在DB上执行的查询
就我对代码的理解而言,您实际上有1+N
查询:第一个是MoviesByTitle
,然后在表达式中有N
查询,该表达式将电影按标题分组。它是N
而不是1
,因为您将query
转换为IEnumerable
,这使它不再是一个查询,而是一个简单的CLR对象,它只是在每次需要GroupHeader
实体时在一个类似foreach
的循环中迭代,向DB发送查询(这是一个实体,不是吗?)
尝试将两个查询合并为一个。您甚至可能不需要使用CompiledQuery
。下面是一个近似代码:
// I left this without changes
if (emptyGroups.Count < 1)
{
characters.ForEach(x => emptyGroups.Add(new Group<Movies>(x, new List<Movies>())));
}
// I put var here, but it actually is an IQueryable<Movie>
var query = from m in App.db.Movies orderby m.Title, m.Year select m;
// Here var is IQueryable<anonymous type>, I just can't use anything else but var here
var groupedMoviesQuery = from t in query
group t by t.GroupHeader into grp
orderby grp.Key
select new
{
Movies = grp,
Header = grp.Key
};
// I use AsEnumerable to mark that what goes after AsEnumerable is to be executed on the client
IEnumerable<Group<Movie>> groupedMovies = groupedMoviesQuery.AsEnumerable()
.Select(x => new Group<Movie>(x.Header, x.Movies))
.ToList();
//No changes here
moviesLongList.ItemsSource = (from t in groupedMovies.AsEnumerable().Union(emptyGroups)
orderby t.Title
select t).ToList();
我假设
GroupHeader
是存储在数据库中的一个实体,与Movie
实体具有1-n关系
首先,我在这里看不到3个DB查询。LINQ表达式并不总是DB查询(例如,存在LINQ to对象)。有时确定真正发生了什么是相当具有挑战性的。在这种情况下,最好的朋友是DB profiler工具或IntelliTrace-它们显示运行时在DB上执行的查询
就我对代码的理解而言,您实际上有1+N
查询:首先是MoviesByTitle
,然后在表达式中有N
查询,该表达式将电影按标题分组。它是N
而不是1
,因为您将query
转换为IEnumerable
,而g> 使它不再是一个查询,而是一个简单的CLR对象,它只是在一个类似于foreach
的循环中迭代,每次需要一个GroupHeader
实体(它是一个实体,不是吗?)
尝试将两个查询合并为一个。您甚至可能不需要使用CompiledQuery
。下面是一个近似代码:
// I left this without changes
if (emptyGroups.Count < 1)
{
characters.ForEach(x => emptyGroups.Add(new Group<Movies>(x, new List<Movies>())));
}
// I put var here, but it actually is an IQueryable<Movie>
var query = from m in App.db.Movies orderby m.Title, m.Year select m;
// Here var is IQueryable<anonymous type>, I just can't use anything else but var here
var groupedMoviesQuery = from t in query
group t by t.GroupHeader into grp
orderby grp.Key
select new
{
Movies = grp,
Header = grp.Key
};
// I use AsEnumerable to mark that what goes after AsEnumerable is to be executed on the client
IEnumerable<Group<Movie>> groupedMovies = groupedMoviesQuery.AsEnumerable()
.Select(x => new Group<Movie>(x.Header, x.Movies))
.ToList();
//No changes here
moviesLongList.ItemsSource = (from t in groupedMovies.AsEnumerable().Union(emptyGroups)
orderby t.Title
select t).ToList();
感谢所有这些。特别是解释-从长远来看,这些知识比直接的代码对我的帮助更大。我使用秒表测试了我的代码,然后在需要优化的地方实现了一些建议。感谢所有这些。特别是解释-从长远来看,这些知识对我的帮助更大我用秒表测试了我的代码,然后在需要优化的地方实现了你的一些建议。
public class Group<T> : IEnumerable<T>
{
public Group(string name, IEnumerable<T> items)
{
this.Title = name;
this.Items = new List<T>(items);
}
public string Title
{
get;
set;
}
public IList<T> Items
{
get;
set;
}
...
}
// I left this without changes
if (emptyGroups.Count < 1)
{
characters.ForEach(x => emptyGroups.Add(new Group<Movies>(x, new List<Movies>())));
}
// I put var here, but it actually is an IQueryable<Movie>
var query = from m in App.db.Movies orderby m.Title, m.Year select m;
// Here var is IQueryable<anonymous type>, I just can't use anything else but var here
var groupedMoviesQuery = from t in query
group t by t.GroupHeader into grp
orderby grp.Key
select new
{
Movies = grp,
Header = grp.Key
};
// I use AsEnumerable to mark that what goes after AsEnumerable is to be executed on the client
IEnumerable<Group<Movie>> groupedMovies = groupedMoviesQuery.AsEnumerable()
.Select(x => new Group<Movie>(x.Header, x.Movies))
.ToList();
//No changes here
moviesLongList.ItemsSource = (from t in groupedMovies.AsEnumerable().Union(emptyGroups)
orderby t.Title
select t).ToList();
class Result
{
public GroupHeader Header {get;set;}
public IEnumerable<Movie> Movies {get;set;}
}
public static Func<MovieDBContext, IQueryable<Result>> GetGroupHeadersWithMovies =
CompiledQuery.Compile((MovieDBContext x) =>
from m in x.Movies
group m by m.GroupHeader into grp
select new Result
{
Movies = grp,
Header = grp.Key
});