【问题标题】:Table doesn't have primary key c# [duplicate]表没有主键c#[重复]
【发布时间】:2013-05-09 15:45:29
【问题描述】:

我试图从DataTable AllItems 中删除行,其中行来自DataTables Items;这样做的目的是从DataTable AllItems 获取不在DataTable Items 内的项目

所有这些行都来自同一个 Excel 文件,该文件包含几列并且是相等的。

我尝试过使用 foreach 循环:

foreach(DataRow dr in AllItems.Rows)
{
if (Items.Contains(dr))
{
AllItems.Rows.Remove(dr);
}

但我收到以下错误:表没有主键。

有谁知道我如何删除这些行?

【问题讨论】:

标签: c# datatable


【解决方案1】:

你可以试试这个:

var exceptItems = AllItems.Rows.Cast<DataRow>()
    .Except(Items.Rows.Cast<DataRow>(), DataRowComparer.Default)
    .ToList();

作为替代方案,如果您想在从中删除 items 行后继续使用 allItems 数据表,您可以试试这个(假设您在两个数据表中都有 Id 列,这唯一标识每个数据表的一行):

var exceptItems = AllItems.Rows.Cast<DataRow>()
    .Select((i, index) => new { id = i["Id"], index })
    .Intersect(Items.Rows.Cast<DataRow>()
        .Select((i, index) => new { id = i["Id"], index }))
    .ToList();

for (int i = exceptItems.Count()-1; i >= 0; i--)
{
    AllItems.Rows.RemoveAt(exceptItems[i].index);
}

这是上面最后一个示例的更好安排:

AllItems.Rows.Cast<DataRow>()
    .Select((i, index) => new { id = i["Id"], index })
    .Intersect(Items.Rows.Cast<DataRow>()
        .Select((i, index) => new { id = i["Id"], index }))
    .OrderByDescending(i => i.index)
    .ToList()
    .ForEach(i => AllItems.Rows.RemoveAt(i.index));

【讨论】:

  • 执行此 AllItems.Count 后不会删除行
  • 您可以使用exceptItems
  • 我添加了两种从AllItems 表中删除Items 行的替代方法。只有当您有一个共同的 Id 列来标识行时,这些才会起作用。
【解决方案2】:

你有几个选择:

1.添加主键

您可以在创建时添加primary key to your data table

假设您有一个名为“Id”的列,那么您会这样做:

AllItems.PrimaryKey = new DataColumn[] { workTable.Columns["Id"] };} 

或者,对于您的主键是复合键(多列)的情况:

AllItems.PrimaryKey = new DataColumn[] { 
                             workTable.Columns["Id"], 
                             workTable.Columns["Name"] };} 

这将使 Contains 正常工作。

2。使用数据视图

您可以使用 DataView 过滤掉不同的行;

DataView view = new DataView(AllItems);
DataTable distinctValues = view.ToTable(true, "Column1", "Column2" , ..., "ColumnN");

3.使用 Select 查找匹配行

或者您可以依赖Select 方法,根据类似于SQL WHEREclause 的语句来测试Items DataTable 中是否存在相应的行:

List<DataRow> rowsToRemove = new List<DataRow>();

foreach(DataRow allItemRow in AllItems.Rows)
{
    if(Items.Select(String.Format("Id = {0}"), 
          allItemRow.Field<Int32>("Id")).Length == 0)
    {
        rowsToRemove.Add(allItemRow);
    }
}

rowsToRemove.ForEach(x => x.Delete());

AllItems.AcceptChanges();

请注意,重要的是不要在迭代 AllItems 中的 Rows 集合时删除行 - 而是收集这些行,然后再删除它们。

4.在途中过滤

另外请注意,我还没有尝试过,但是,根据您从 Excel 中选择行的方式,您可以使用 SQL DISTINCT 子句;如果您使用的是ODBC to load data from Excel,那么您可以尝试从源头过滤。

【讨论】:

    猜你喜欢
    • 2017-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 2013-04-01
    相关资源
    最近更新 更多