4

在如下的 Linq 语句中(缩小到问题的相关部分):

var sites = from s in DataContext.Sites
            join add in DataContext.Address 
              on s.PrimaryAddress equals add into sa
    from a in sa.DefaultIfEmpty()
            select new {
                        s.Id,
                        s.SiteName,
                        PrimaryAddress = a
                       };

我们遇到的问题是,最终基于 GridView/LinqDataSource 组合的控件无法在 PrimaryAddress 连接类上正确排序(忽略它)。对于像这样的所有加入的类,我们都看到了相同的行为。GridView 有什么办法来处理这个问题吗? 或者,有没有一种通过表达式的方法,我们可以在动态 OrderBy 的代码中处理它?

附加说明: 添加时.OrderBy(s => s.PrimaryAddress)我们得到Cannot order by type 'Address',当.OrderBy(gs => gs.PrimaryBusinessAddress.AddressLine1)我们得到Specified method is not supported. 对 LinqDataSource.OrderBy 本身进行排序时,为时已晚......它只对当前页面上的记录进行排序,而不是对整个集合进行排序。

为清楚起见,这是网格中地址的格式:

public partial class Address
{
  public override string ToString()
  {
    return string.Format("{0} {1}{2} {3}",
    AddressLine1,
    City,
    !string.IsNullOrEmpty(State) && State != "None" ? ", " + State : string.Empty,
    !string.IsNullOrEmpty(Country) ? string.Format("({0})", Country) : string.Empty);
  }
}

如果我们可以按 排序AddressLine1 + City + State + Country,那就足够了,但我不确定如何通过表达式树来做到这一点......无论我们通过表达式指定什么 OrderBy,它都会恢复为按s.SiteName排序(默认排序在网格上)。在我们的网格控件中显示的像这样的连接类的数量非常有限,每个都有一个开关和表达式案例根本不是问题。关于解决方案或完全不同的方法的任何想法?

4

3 回答 3

3

我习惯于在代码中使用 Linq to Entities,但我在 LINQPad 中使用 LINQ to SQL 的次数已经足够多,以至于我已经相当熟悉它了。我不完全确定我了解您在哪里遇到困难,但我认为以下应该可行:

var sites = from s in DataContext.Sites
            orderby s.PrimaryAddress.AddressLine1,
                     s.PrimaryAddress.City,
                     s.PrimaryAddress.State,
                     s.PrimaryAddress.Country
            select new 
            {
                s.Id,
                s.SiteName,
                s.PrimaryAddress
            };

如果有什么我不明白的,请告诉我。

更新

我不确定为什么这对你不起作用。我刚刚在 LINQPad(LINQ to SQL 模式)中做了以下操作:

from p in person
orderby p.clue_type.clue_type_id,
        p.clue_type.clue_type
select new
{
    p.person_id, p.clue_type
}

结果都是有线索类型=空的。LINQ to SQL 只是将空引用视为具有全空属性的值。这是生成的 SQL:

SELECT TOP (10) [t0].[person_id], [t2].[test], [t2].[clue_type_id], [t2].[clue_type]
FROM [person] AS [t0]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t1].[clue_type_id], [t1].[clue_type]
    FROM [clue_types] AS [t1]
    ) AS [t2] ON [t2].[clue_type_id] = [t0].[clue_type_id]
ORDER BY [t2].[clue_type_id], [t2].[clue_type]

注意左连接。这不会满足您的要求吗?

更新 2

使查询动态化可能相当困难,具体取决于您的动态化程度。如果您希望能够根据传递给您的方法的字符串值对返回的任何属性进行排序,这是一个解决方案:

public class SiteDisplayInfo
{
    public int Id {get;set;}
    public string SiteName {get;set;}
    public string PrimaryAddress {get;set;}

    public static readonly Dictionary<string, Func<IQueryable<Site>, IOrderedQueryable<Site>>> OrderByFuncs = 
    new Dictionary<string, Func<IQueryable<Site>, IOrderedQueryable<Site>>>
    {
        {"Id", q => q.OrderBy(s => s.Id)},
        {"SiteName", q => q.OrderBy(s => s.SiteName)},
        {"PrimaryAddress", 
        q => q.OrderBy(s => s.PrimaryAddress.AddressLine1)
                             .ThenBy(s => s.PrimaryAddress.City)}
    };
}

...

public IEnumerable<SiteDisplayInfo> GetSites(string orderByString)
{
    IQueryable<Site> sites = DataBase.Sites;
    if (orderByString != null && SiteDisplayInfo.OrderByFuncs.ContainsKey(orderByString))
    {
        sites = SiteDisplayInfo.OrderByFuncs[orderByString](sites);
    }
    var query = from s in sites
                select new SiteDisplayInfo
                {
                    Id = s.Id,
                    SiteName = s.SiteName,
                    PrimaryAddress = s.PrimaryAddress.AddressLine1 + s.PrimaryAddress.City
                };
    return query.ToList();
}

还有其他一些方法可以做类似的事情,但这给了你一个大致的想法。

于 2009-09-30T19:58:05.120 回答
2

我刚刚尝试了与您所拥有的类似的设置,这应该可以:

var sites = from s in dc.Sites
    join addr in dc.Addresses
        on s.PrimaryAddress equals addr into sa
    from a in sa.DefaultIfEmpty()
    orderby a.AddressLine1, a.City, a.State, a.Country /* insert orderby here */
    select new
        {
            s.Id,
            s.SiteName,
            PrimaryAddress = a
        };

如果要更改 orderby 的方向,只需在每一列中添加降序:

orderby a.AddressLine1 descending, a.City descending, a.State descending, a.Country descending

尽管这种方法有效,但它并不完全是动态的。您必须重写查询以按其他方向或列顺序进行排序。

如果这是您想要的,我建议您使用带有一些额外管道的方法方法,或者使用允许您将列名指定为文字的动态 OrderBy 的完全动态方法。对于后者,请查看本主题和本博文

于 2009-10-02T11:38:55.950 回答
0

添加 .OrderBy(s => s.PrimaryAddress) 时,我们得到 Cannot order by type 'Address'

那是因为 PrimaryAddress 只存在于代码中。LINQ 语句将发出并获取所有行以创建地址,然后在代码中将它们合并在一起。您是否尝试过某种形式的 .OrderBy(a => a.Address) ?即,引用子表的列而不是您的派生名称。

于 2009-09-25T12:35:18.953 回答