提问人:Sapri s 提问时间:7/31/2023 最后编辑:ani HSapri s 更新时间:8/2/2023 访问量:94
使用 Linq C 从 Id 匹配的另一个 List<T> 对象中查找一个 List<T> 对象中的不匹配行#
Finding the unmatched rows in one List<T> object from another List<T> object where Id matches using Linq C#
问:
我有一个包含一组记录的 Excel 文件,并且有一个包含一组记录的数据库。我正在做的是将数据库和 Excel 都更改为列表,并将两条记录与名为 .UserTable
UserId
现在我想用 list2(从 Excel 工作表)更新(从数据库)。如果两个列表中的字段匹配,而任何其他字段不匹配,则必须在 中更新。list1
usertable
UserId
list1
我尝试了这段代码:
public void Update(List<UserTable> users, List<UserTable> mappeddata)
{
var valuetoupdate = mappeddata.IntersectBy(users.Select(y => y.UserId), y => y.UserId, StringComparer.OrdinalIgnoreCase);
var rowsToUpdate = valuetoupdate.Except(users, new UserTableEqualityComparer());
}
public class UserTableEqualityComparer : IEqualityComparer<UserTable>
{
public bool Equals(UserTable x, UserTable y)
{
if (x == null || y == null)
return false;
else
return
(string.Equals(x.ManagerUserId, y.ManagerUserId, StringComparison.OrdinalIgnoreCase) &&
string.Equals(x.Department, y.Department, StringComparison.OrdinalIgnoreCase) &&
string.Equals(x.Title, y.Title, StringComparison.OrdinalIgnoreCase)
...//rest of the field
);
}
public int GetHashCode(UserTable obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + (obj.ManagerUserId?.ToLower().GetHashCode() ?? 0);
hash = hash * 23 + (obj.Department?.ToLower().GetHashCode() ?? 0);
hash = hash * 23 + (obj.Title?.ToLower().GetHashCode() ? 0);
...//rest of the field
return hash;
}
}
}
谢谢!
答:
0赞
Guru Stron
7/31/2023
#1
首先,我会将源数据更改为字典:
List<UserTable> mappeddata = ...;
var dict = mappeddata
.GroupBy(t => t.UserId) // or .GroupBy(t => t.UserId, StringComparer.OrdinalIgnoreCase)
.ToDictionary(g => g.Key, g => g.First()); // possibly need some logic to handle duplicates
如果使用 EF Core,则一个选项是仅依赖其更改跟踪器(尽管它将执行区分大小写的比较):
var fromDb = _ctx.UserTable
.Where(t => dict.Keys.Contains(t.UserId)) // no need to fetch all users, fetch only existing in the dictionary
.ToList();
foreach (var ut in fromDb)
{
var source = dict[ut.UserId];
// ... map data
}
_ctx.SaveChanges(); // will update only data with changed values
仅当数据实际发生更改时,EF Core 才应更新数据。
如果您需要使用不区分大小写的比较,我不会使用比较器方法。
var toUpdate = fromDb
.Where(t =>
{
var source = dict[t.UserId];
return !string.Equals(t.ManagerUserId, source.ManagerUserId, StringComparison.OrdinalIgnoreCase)
|| !string.Equals(t.Department, source.Department, StringComparison.OrdinalIgnoreCase);
});
foreach (var ut in toUpdate)
{
var source = dict[ut.UserId];
// ... map data
}
如果你想坚持管理 2 个列表,那么你可以稍微修改第二种方法:
var toUpdate = users
.Where(t => dict.ContainsKey(t.UserId)) // filter out not present in the data
.Where(t =>
{
var source = dict[t.UserId];
return !string.Equals(t.ManagerUserId, source.ManagerUserId, StringComparison.OrdinalIgnoreCase)
|| !string.Equals(t.Department, source.Department, StringComparison.OrdinalIgnoreCase);
})
.ToList();
评论
0赞
Sapri s
7/31/2023
你能解释一下吗,我不明白。您是尝试直接更新数据库还是更新列表。我正在做的是,我已将 database(usertable) 转换为 list1 并将 excel 转换为 list2,并将更改存储在 list3 中。我正在生成更新语句以从 list3 更新日期库。谢谢。
0赞
Guru Stron
7/31/2023
@Sapris EF Core 使用更改跟踪,因此,如果已通过 EF Core 提取实体(启用跟踪),然后更改了这些实体中的字段,则 EF 将仅传播更改,仅实际更改了数据。没有必要使用 ,但如果你愿意,你可以从第二个代码片段中构建它(参见更新)。list3
toUpdate
0赞
Sapri s
8/1/2023
我尝试了最后一个,但我得到了 0 作为输出。它不起作用
0赞
Guru Stron
8/1/2023
@Sapris请提供一个完整的最小可重现示例(以便可以编译和运行并显示问题)
0赞
Sapri s
8/2/2023
我已经相应地更改了我的代码。
0赞
Enigmativity
8/2/2023
#2
我不明白你为什么不做这样简单的事情?
public void Update(List<UserTable> users, List<UserTable> mappeddata)
{
var rowsToUpdate =
from m in mappeddata
join u in users on m.UserId equals u.UserId
where
m.ManagerUserId != u.ManagerUserId
|| m.Department != u.Department
|| m.Title != u.Title
select m;
}
我知道我没有通过忽略大小写来做到这一点,你应该明白了。
评论