使用 LINQ to select 两个表之间的不同值
Using LINQ to select distinct values between two tables
我有一个类似于以下信息的数据集。
我想做的是用尽可能多的可用信息填充一个对象。
所以我想从顶部数据集中获取 UnitNum 65002,其余从单列 table。
我的代码:
foreach (DataRow row in dsUnits.Tables[0].Rows)
{
var unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString(),
CustCode = row["CustCode"].NullSafeToString(),
Year = row["Year"].NullSafeToString(),
Make = row["Make"].NullSafeToString(),
Model = row["Model"].NullSafeToString()
};
UnitsInvolvedInBreakdown.Add(unit);
}
foreach (DataRow row in dsUnits.Tables[1].Rows)
{
if (UnitsInvolvedInBreakdown.Where(x => x.UnitNum == row["UnitNumber"].ToString()).Count() == 0)
{
var unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].ToString()
};
UnitsInvolvedInBreakdown.Add(unit);
}
}
这对我来说似乎效率很低,我尝试了下面的代码但没有结果,
var q = dsUnits.Tables[0].AsEnumerable().Except(dsUnits.Tables[1].AsEnumerable());
我的问题基本上是,有没有一种方法可以使用 linq 到 table 0 中的 select UnitNumbers,前提是它们不存在于 table 1
中
更好的解释。
单元号将在table 1.它可能在table 0.
如果它在 table 0 中,我想从那里获取信息..我有更多信息。
如果它不在 table 0 中,我想从 table 1 中获取信息,因为我必须尽我所能。但我不想重复。
如果我理解了您的要求,这就是您要找的。它首先从 table 中获取所有内容,然后通过 Linq Left-Outer-Join 获取所有不在 table 中但在 table 中的内容:
var unitsFrom1 = dsUnits.Tables[0].AsEnumerable()
.Select(row => new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString(),
CustCode = row["CustCode"].NullSafeToString(),
Year = row["Year"].NullSafeToString(),
Make = row["Make"].NullSafeToString(),
Model = row["Model"].NullSafeToString()
});
var unitsFrom2Notin1 =
from row in dsUnits.Tables[1].AsEnumerable()
join u1 in unitsFrom1
on row.Field<string>("UnitNumber") equals u1.UnitNum into outer
from outerJoin in outer.DefaultIfEmpty()
where outerJoin == null
select new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString()
};
现在您可以连接两者:
IEnumerable<Unit.Unit> result = unitsFrom1.Concat(unitsFrom2Notin1);
这是一种更易于维护并且在任何情况下都应该有效的不同方法。您可以实现自定义 IEqualityComparer<Unit>
,您可以将其用于许多(基于集合的)LINQ 方法,例如 Join
、Intersect
、Union
、GroupBy
。您也可以将它用于 HashSet<Unit.Unit>
,在这种情况下我更喜欢。这是 UnitComparer
:
的可能实现
public class UnitComparer : IEqualityComparer<Unit>
{
public bool Equals(Unit x, Unit y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.UnitNum == y.UnitNum;
}
public int GetHashCode(Unit obj)
{
return obj == null || obj.UnitNum == null ? 0 : obj.UnitNum.GetHashCode();
}
}
这里是你需要的简单循环,从第一个开始,所有不在第一个的从第二个开始。请注意我使用的 HashSet<T>
constructor:
var uniqueUnits = new HashSet<Unit.Unit>(new Unit.UnitComparer());
foreach (DataRow row in dsUnits.Tables[0].Rows)
{
Unit.Unit unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString(),
CustCode = row["CustCode"].NullSafeToString(),
Year = row["Year"].NullSafeToString(),
Make = row["Make"].NullSafeToString(),
Model = row["Model"].NullSafeToString()
};
uniqueUnits.Add(unit);
}
foreach (DataRow row in dsUnits.Tables[1].Rows)
{
Unit.Unit unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString()
};
uniqueUnits.Add(unit);
}
HashSet<T>.Add
returns false
如果因为已经在集合中而无法添加。
我发现当我处于 linq 思维模式时,数据集往往会让我失望。我发现通过 类 构建实体然后使用 linq 查询实体更容易。由于时间不够,我复制了一个 MSDN 示例。您可以根据需要修改它。
var query =
from contact in contacts
from order in orders
where contact.ContactID == order.Contact.ContactID
&& order.TotalDue < totalDue
select new
{
ContactID = contact.ContactID,
LastName = contact.LastName,
FirstName = contact.FirstName,
OrderID = order.SalesOrderID,
Total = order.TotalDue
};
foreach (var smallOrder in query)
{
Console.WriteLine("Contact ID: {0} Name: {1}, {2} Order ID: {3} Total Due: ",
smallOrder.ContactID, smallOrder.LastName, smallOrder.FirstName,
smallOrder.OrderID, smallOrder.Total);
}
}
我有一个类似于以下信息的数据集。
我想做的是用尽可能多的可用信息填充一个对象。
所以我想从顶部数据集中获取 UnitNum 65002,其余从单列 table。
我的代码:
foreach (DataRow row in dsUnits.Tables[0].Rows)
{
var unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString(),
CustCode = row["CustCode"].NullSafeToString(),
Year = row["Year"].NullSafeToString(),
Make = row["Make"].NullSafeToString(),
Model = row["Model"].NullSafeToString()
};
UnitsInvolvedInBreakdown.Add(unit);
}
foreach (DataRow row in dsUnits.Tables[1].Rows)
{
if (UnitsInvolvedInBreakdown.Where(x => x.UnitNum == row["UnitNumber"].ToString()).Count() == 0)
{
var unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].ToString()
};
UnitsInvolvedInBreakdown.Add(unit);
}
}
这对我来说似乎效率很低,我尝试了下面的代码但没有结果,
var q = dsUnits.Tables[0].AsEnumerable().Except(dsUnits.Tables[1].AsEnumerable());
我的问题基本上是,有没有一种方法可以使用 linq 到 table 0 中的 select UnitNumbers,前提是它们不存在于 table 1
中更好的解释。
单元号将在table 1.它可能在table 0.
如果它在 table 0 中,我想从那里获取信息..我有更多信息。
如果它不在 table 0 中,我想从 table 1 中获取信息,因为我必须尽我所能。但我不想重复。
如果我理解了您的要求,这就是您要找的。它首先从 table 中获取所有内容,然后通过 Linq Left-Outer-Join 获取所有不在 table 中但在 table 中的内容:
var unitsFrom1 = dsUnits.Tables[0].AsEnumerable()
.Select(row => new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString(),
CustCode = row["CustCode"].NullSafeToString(),
Year = row["Year"].NullSafeToString(),
Make = row["Make"].NullSafeToString(),
Model = row["Model"].NullSafeToString()
});
var unitsFrom2Notin1 =
from row in dsUnits.Tables[1].AsEnumerable()
join u1 in unitsFrom1
on row.Field<string>("UnitNumber") equals u1.UnitNum into outer
from outerJoin in outer.DefaultIfEmpty()
where outerJoin == null
select new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString()
};
现在您可以连接两者:
IEnumerable<Unit.Unit> result = unitsFrom1.Concat(unitsFrom2Notin1);
这是一种更易于维护并且在任何情况下都应该有效的不同方法。您可以实现自定义 IEqualityComparer<Unit>
,您可以将其用于许多(基于集合的)LINQ 方法,例如 Join
、Intersect
、Union
、GroupBy
。您也可以将它用于 HashSet<Unit.Unit>
,在这种情况下我更喜欢。这是 UnitComparer
:
public class UnitComparer : IEqualityComparer<Unit>
{
public bool Equals(Unit x, Unit y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.UnitNum == y.UnitNum;
}
public int GetHashCode(Unit obj)
{
return obj == null || obj.UnitNum == null ? 0 : obj.UnitNum.GetHashCode();
}
}
这里是你需要的简单循环,从第一个开始,所有不在第一个的从第二个开始。请注意我使用的 HashSet<T>
constructor:
var uniqueUnits = new HashSet<Unit.Unit>(new Unit.UnitComparer());
foreach (DataRow row in dsUnits.Tables[0].Rows)
{
Unit.Unit unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString(),
CustCode = row["CustCode"].NullSafeToString(),
Year = row["Year"].NullSafeToString(),
Make = row["Make"].NullSafeToString(),
Model = row["Model"].NullSafeToString()
};
uniqueUnits.Add(unit);
}
foreach (DataRow row in dsUnits.Tables[1].Rows)
{
Unit.Unit unit = new Unit.Unit
{
UnitNum = row["UnitNumber"].NullSafeToString()
};
uniqueUnits.Add(unit);
}
HashSet<T>.Add
returns false
如果因为已经在集合中而无法添加。
我发现当我处于 linq 思维模式时,数据集往往会让我失望。我发现通过 类 构建实体然后使用 linq 查询实体更容易。由于时间不够,我复制了一个 MSDN 示例。您可以根据需要修改它。
var query =
from contact in contacts
from order in orders
where contact.ContactID == order.Contact.ContactID
&& order.TotalDue < totalDue
select new
{
ContactID = contact.ContactID,
LastName = contact.LastName,
FirstName = contact.FirstName,
OrderID = order.SalesOrderID,
Total = order.TotalDue
};
foreach (var smallOrder in query)
{
Console.WriteLine("Contact ID: {0} Name: {1}, {2} Order ID: {3} Total Due: ",
smallOrder.ContactID, smallOrder.LastName, smallOrder.FirstName,
smallOrder.OrderID, smallOrder.Total);
}
}