Linq 在 DataTable 中进行 not in 选择查询

4

你好,我有两个数据表格(bannedlist和countrylist),它们都包含国家名称和代码在cc和country列中。我想进行一个查询,在countrylist表格中选择未在bannedlist表格中的国家,以创建第三个表格。

你有什么想法吗?

我对此还没有深入了解。

        var ccList = ds.Tables[2].AsEnumerable(); 
        var bannedCCList = ds.Tables[1].AsEnumerable();
        var query = from r in ccList....

..

after trying

var bannedCCList = ds.Tables[1].AsEnumerable();
    var query = from r in ccList where !bannedCCList.Any(b => b["cc"] == r["cc"])select r;

我仍然得到相同的国家列表,被禁止的国家尚未被删除。以下是更详细的说明来解释更多情况。不确定我做错了什么。
 protected void BindCountryBan(string subd)
{
    DataSet ds = new DataSet();
    ds = new DB().CountryBan_GetSiteSettings();

        BannedCountryListBox.DataSource = ds.Tables[1];
        BannedCountryListBox.DataValueField = "cc";
        BannedCountryListBox.DataTextField = "country";
        BannedCountryListBox.DataBind();

//bind country list
    var ccList = ds.Tables[2].AsEnumerable(); 
    var bannedCCList = ds.Tables[1].AsEnumerable();
    var query = from r in ccList where !bannedCCList.Any(b => b["cc"] == r["cc"])select r;
    //var query = ccList.Except(bannedCCList); 




    //CountryListBox.DataSource = ds.Tables[2];
    DataTable boundTable = query.CopyToDataTable<DataRow>();
    CountryListBox.DataSource = boundTable;
    CountryListBox.DataValueField = "cc";
    CountryListBox.DataTextField = "country";
    CountryListBox.DataBind();
}

重新思考了我的问题后,我意识到,与其试图玩弄并解决它,不如在我的SQL查询中添加一个小的where子句:“Select * from country_list where cc not in(select cc from country_list_banned_countries where subdomain=@subdomain ) order by country asc”,这样我就可以从服务器端提取被禁止的国家列表并轻松绑定。感谢大家。 - nLL
3个回答

8

如果您在国家序列上使用Except,它将起作用:

using System.Linq;
...

    var ccList = from c in ds.Tables[2].AsEnumerable()
                 select c.Field<string>("Country"); 
    var bannedCCList = from c in ds.Tables[1].AsEnumerable()
                       select c.Field<string>("Country");
    var exceptBanned = ccList.Except(bannedCCList);

如果您需要完整的行数据而国家没有被禁止,您可以尝试左外连接:
    var ccList = ds.Tables[2].AsEnumerable();
    var bannedCCList = ds.Tables[1].AsEnumerable();
    var exceptBanned = from c in ccList
                       join b in bannedCCList
                         on c.Field<string>("Country") equals b.Field<string>("Country") into j
                       from x in j.DefaultIfEmpty()
                       where x == null
                       select c;

谢谢!你的左外连接按照我的预期工作了,还有一个问题请教。请看一下我在Meta-Knight答案中的注释。我通过将查询结果转换为表格来将结果绑定到列表框中。是否有更好的绑定方式? - nLL
尝试将ListBox的DataTextField和DataValueField值设置为您想要绑定的字段名称。您不需要复制到表中。 - dahlbyk
请 "dahlbyk",我需要 VB.Net 中的第二个代码,我在使用 "http://converter.telerik.com/" 进行转换时遇到了问题,提前感谢。 - Beldi Anouar

5
您可以像这样使用Except() LINQ扩展方法:
var result = full.Except(banned);

然而,这对于所包含类型的默认比较器来说是有效的。因此,如果您想像您的示例中那样使用特定列,您可能需要另一种方法,如下所示:
from r in ccList
where !bannedCCList.Any(b => b["cc"] == r["cc"])
select r;

使用Except()意味着两个集合中的引用是相同的,但我认为在表格中并非如此,如果我错了,请纠正我。

太棒了!我需要将一个List<EF类型>与一个数据表格结合起来,我对你的示例稍作修改,结果非常完美。 - DaniDev

2

试试这个:

var query = ccList.Except(bannedCCList);

你需要:using System.Linq; - DanDan
当我将查询绑定到列表框时,我只得到了 System.Data.DataRow,看起来我又做错了什么。 - nLL
好的,我已经使用以下代码将其转换为 DataTable: DataTable boundTable = query.CopyToDataTable<DataRow>(); 但我不确定这是否是最佳方法。 - nLL
虽然这也可以是一种解决方案,但对于较少的记录来说速度很快,而当列表达到20万时,这种方法将非常缓慢。 - superachu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接