如何在自引用表中给出以下路由别名,以获取最后一个类别

时间:2013-04-03 18:50:43

标签: c# linq entity-framework

我的问题解决方法就像这样的代码;

    string permalink = "computers/hp/computers"; //example for similarity
    List<string> aliases = permalink.Split('/').ToList();

    Category cat = db.Categories.SingleOrDefault(c => c.Alias == aliases.First());
    aliases.Remove(aliases.First());

    foreach (string alias in aliases)
    {
        cat = cat.Categories.SingleOrDefault(c => c.Alias == alias);
    }

    return cat;

但这是多次查询..

我该怎么做一次?

3 个答案:

答案 0 :(得分:0)

如果我了解您的需求,可以使用Enumerable.Aggregate方法。您必须从“根”类别开始,该类别包含db.Categories的所有内容。虽然这很容易嘲笑。试试这个:

var aliases = permalink.Split('/');
var category = new Category // start with a 'root' category
{
    Id = 0, 
    Categories = db.Categories 
}; 
var cat = aliases.Aggregate(category, (c, a) => c.Categories.SingleOrDefault(x => x.Alias == a));

答案 1 :(得分:0)

首先,如果类别表很小,有时最好只抓住整个表并在内存中进行选择(可能使用p.w.s.g的答案)。

如果表很大,那么存储过程可能会比Linq好。

但是,如果你真的想在Linq中这样做,那么我认为唯一的方法是重复向同一个表添加一个连接。

以下假设您的关系位于名为ParentID和Id的字段之间。我还更改了你的字符串固定链接以更好地说明顺序。

你首先需要一个小帮手类

public class Info
{
    public Category category;
    public int? recordID;
}

然后是您的主要代码

string permalink ="computers1/hp/computers2"; 
var aliases = permalink.Split('/');

var query = dc.Categories.Where(r=>r.Alias == aliases[aliases.Length-1])
              .Select(r=> new Info { category = r,  recordID = r.ParentID});

    for(int i = aliases.Length -2 ; i >= 0; i--)
    {
        string alias = aliases[i]; 
        query =  query.Join(dc.Categories , 
                            a => a.recordID , b => b.Id , (a,b) => new { a , b} )
        .Where(r=>r.b.Alias == alias)
        .Select(r=> new Info { category = r.a.category, recordID = r.b.ParentID});
    }

    return query.SingleOrDefault().category;

正如你可以看到join的lambda语法是(恕我直言)可怕而且我通常会试图避免它,但我无法想到在这里避免它。

由于我无法测试它,它可能完全错误(也许我已经混淆了ID,ParentID或我的a和b),因此测试它并测试它的执行方式非常重要。

我认为生成的sql应该是

SELECT * from Categories AS t0
INNER JOIN Categories AS t1 ON t0.ParentID = t1.id
INNER JOIN Categories AS t2 ON t1.ParentID = t2.id
WHERE t2.Alias = 'computers1' 
  AND t1.Alias = 'hp' 
  AND t0.Alias = 'computers2'

部分或别名越多,那么连接就越多。

现在你已经看到了所有这些,你可能想避免使用这种方法 - )

答案 2 :(得分:0)

我可能只会增加你的困惑:),但让我抛出一个想法......
我只想说这不起作用(完全符合您的规格) - 它不是解决方案,但可能会帮助您简化一些事情。

var query = 
    (from cat in db.Categories
     where cat.Alias == "mainAalias"
     from subcat in cat.Categories
     where aliases.Contains(subcat.Alias)
     orderby subcat.Alias descending
     select subcat);  
query.FirstOrDefault(); // or something

这应该产生一个相对简单的查询
(例如SELECT...FROM...JOIN...WHERE... AND...IN...ORDERBY...)。

e.g。如果你给它'cat1','cat2'......'cat6' - 从cat1到cat100 - 它给'cat6'...'cat1'(我的意思是别名)

然而,“排序”存在一个主要的“缺陷” - 您的规格要求排序是“别名”as they come的顺序 - 这对查询来说有点不幸。如果您可以以某种方式强制执行或定义可以转换为SQL的订单,则此(或类似)可能有效。

  

我假设 - 你的'别名'是按升序预先排序的   order - 使此查询起作用。他们不是,我知道   这一点。

但我认为你的想法在这里没有明确定义(以及为什么我们所有人都遇到问题) - 仔细考虑并优化 - 简化您的要求 - 并让您的C#等级帮助,例如通过预先排序。

你也可以尝试某种形式的'分组'每只猫.Alias等 - 但我认为同样的'排序问题'仍然存在。