使用 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#

提问人:Sapri s 提问时间:7/31/2023 最后编辑:ani HSapri s 更新时间:8/2/2023 访问量:94

问:

我有一个包含一组记录的 Excel 文件,并且有一个包含一组记录的数据库。我正在做的是将数据库和 Excel 都更改为列表,并将两条记录与名为 .UserTableUserId

现在我想用 list2(从 Excel 工作表)更新(从数据库)。如果两个列表中的字段匹配,而任何其他字段不匹配,则必须在 中更新。list1usertableUserIdlist1

我尝试了这段代码:

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;
        }
    } 
}

谢谢!

C# Excel 列表 LINQ

评论

0赞 Dale K 7/31/2023
您已经标记了 SQL Server 和 Excel,但您正在寻找的解决方案本身似乎不需要这些领域的专家?
0赞 Sapri s 7/31/2023
我会纠正它,但我已将我的 Excel 和数据库更改为列表对象
0赞 Guru Stron 7/31/2023
您使用什么来访问数据库?有没有可能是EF?
0赞 Sapri s 7/31/2023
是的,我正在使用 EFcore
0赞 Enigmativity 8/2/2023
你在问什么问题?你已经发表了一堆声明,但没有问题。

答:

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 将仅传播更改,仅实际更改了数据。没有必要使用 ,但如果你愿意,你可以从第二个代码片段中构建它(参见更新)。list3toUpdate
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;
}

我知道我没有通过忽略大小写来做到这一点,你应该明白了。