Skip to content

Commit

Permalink
[feat]新增Merge,已有数据集合并新数据集,未存在时插入、存在时更新、多余则删除,常用于更新统计表
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Aug 26, 2024
1 parent 33611a5 commit 91988b0
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 3 deletions.
10 changes: 7 additions & 3 deletions XCode/Entity/EntityBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ public Boolean SetItem(String name, Object? value)
/// <returns></returns>
internal protected abstract IEntity CloneEntityInternal(Boolean setDirty = true);

/// <summary>复制来自指定模型的成员,可以是不同类型</summary>
/// <summary>复制来自指定模型的成员,可以是不同类型。脏数据用于控制局部复制</summary>
/// <param name="model">来源实体对象</param>
/// <param name="setDirty">是否设置脏数据</param>
/// <param name="setDirty">是否设置脏数据。默认true,仅拷贝有脏数据的源字段,也设置目标脏数据</param>
/// <returns>实际复制成员数</returns>
public virtual Int32 CopyFrom(IModel model, Boolean setDirty = true)
{
Expand All @@ -146,7 +146,11 @@ public virtual Int32 CopyFrom(IModel model, Boolean setDirty = true)
if (destNames.Contains(item))
{
if (setDirty)
dest.SetItem(item, source[item]);
{
// 启用脏数据,仅复制有脏数据的字段,同时避免拷贝主键
if (source.Dirtys[item])
dest.SetItem(item, source[item]);
}
else
dest[item] = source[item];
}
Expand Down
80 changes: 80 additions & 0 deletions XCode/Entity/EntityExtension.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using NewLife;
using NewLife.Data;
Expand Down Expand Up @@ -1001,6 +1002,85 @@ public static Int32 Upsert(this IEntity entity, BatchOption? option = null, IEnt
}
}

/// <summary>已有数据集合并新数据集,未存在时插入、存在时更新、多余则删除,常用于更新统计表</summary>
/// <remarks>
/// 合并操作应用于实体层,不同于数据库的MergeTo。
/// 常用于数据分析场景,将新数据合并到已有数据中,已有数据中没有的数据插入,已有数据中有的数据更新,已有数据中多余的数据删除。
/// 数据统计时,为了方便会构建新的数据集,然后合并到已有数据集中。
/// </remarks>
/// <typeparam name="T">已有数据集实体类型</typeparam>
/// <typeparam name="T2">新数据集实体类型</typeparam>
/// <param name="source">已有数据集。例如:该日已有统计数据列表</param>
/// <param name="news">新数据集。例如:根据原始数据统计得到的数据列表</param>
/// <param name="keys">业务主键。比较新旧两行统计对象的业务主键是否相同</param>
/// <param name="trim">删除多余数据。默认true</param>
/// <returns></returns>
public static IList<T> Merge<T, T2>(this IList<T> source, IEnumerable<T2> news, String[] keys, Boolean trim = true) where T : class, IEntity where T2 : IModel => source.Merge(news, (x, y) => keys.All(k => x[k] == y[k]), trim);

/// <summary>已有数据集合并新数据集,未存在时插入、存在时更新、多余则删除,常用于更新统计表</summary>
/// <remarks>
/// 合并操作应用于实体层,不同于数据库的MergeTo。
/// 常用于数据分析场景,将新数据合并到已有数据中,已有数据中没有的数据插入,已有数据中有的数据更新,已有数据中多余的数据删除。
/// 数据统计时,为了方便会构建新的数据集,然后合并到已有数据集中。
/// </remarks>
/// <typeparam name="T">数据集实体类型</typeparam>
/// <param name="source">已有数据集。例如:该日已有统计数据列表</param>
/// <param name="news">新数据集。例如:根据原始数据统计得到的数据列表</param>
/// <param name="comparer">比较器。比较新旧两行统计对象是否相同业务维度</param>
/// <param name="trim">删除多余数据。默认true</param>
/// <returns></returns>
public static IList<T> Merge<T>(this IList<T> source, IEnumerable<T> news, IEqualityComparer<T> comparer, Boolean trim = true) where T : class, IEntity => source.Merge(news, comparer.Equals, trim);

/// <summary>已有数据集合并新数据集,未存在时插入、存在时更新、多余则删除,常用于更新统计表</summary>
/// <remarks>
/// 合并操作应用于实体层,不同于数据库的MergeTo。
/// 常用于数据分析场景,将新数据合并到已有数据中,已有数据中没有的数据插入,已有数据中有的数据更新,已有数据中多余的数据删除。
/// 数据统计时,为了方便会构建新的数据集,然后合并到已有数据集中。
/// </remarks>
/// <typeparam name="T">已有数据集实体类型</typeparam>
/// <typeparam name="T2">新数据集实体类型</typeparam>
/// <param name="source">已有数据集。例如:该日已有统计数据列表</param>
/// <param name="news">新数据集。例如:根据原始数据统计得到的数据列表</param>
/// <param name="predicate">比较器。比较新旧两行统计对象是否相同业务维度</param>
/// <param name="trim">删除多余数据。默认true</param>
/// <returns></returns>
public static IList<T> Merge<T, T2>(this IList<T> source, IEnumerable<T2> news, Func<T, T2, Boolean> predicate, Boolean trim = true) where T : class, IEntity where T2 : IModel
{
var rs = new List<T>();
var fact = typeof(T).AsFactory();
foreach (var model in news)
{
var entity = source.FirstOrDefault(e => predicate(e, model));
if (entity == null)
{
entity = model as T;
if (entity == null)
{
entity = (T)fact.Create(true);
entity.CopyFrom(model, true);
}

rs.Add(entity);
}
else
{
// 启用脏数据,仅复制有脏数据的字段,同时避免拷贝主键
entity.CopyFrom(model, true);

rs.Add(entity);
source.Remove(entity);
}
}

// 删除多余的
if (trim) source.Delete(true);

// 保存数据,插入或更新
rs.Save();

return rs;
}

/// <summary>获取可用于插入的数据列</summary>
/// <param name="fact"></param>
/// <param name="list"></param>
Expand Down

0 comments on commit 91988b0

Please sign in to comment.