C# 将Linq2SQL简单查询转换为CompiledQuery以提高应用程序性能

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

我正在编写一个Silverlight for Windows Phone(SDK 7.1)应用程序,并在Windows Phone Silverlight Toolkit的
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
      });