既然是反序列得到的值,直接赋值就行了。这里不需要SetItem,因为SetItem会设置脏数据,在实体对象很多时(>100w)造成巨大的内存开销。这个修改,导致Area加载csv数据再批量导入数据库时,没有脏数据造成字段数据丢失,因此需要显式指定FullInsert

This commit is contained in:
大石头 2025-07-30 18:13:39 +08:00
parent 85284874cb
commit 70df4522c4
5 changed files with 52 additions and 21 deletions

View File

@ -1951,7 +1951,9 @@ public partial class Entity<TEntity> : EntityBase, IAccessor where TEntity : Ent
if (!binary.TryRead(fi.Type, ref value)) return false;
// 顺序要求很高
SetItem(fi.Name, value);
//SetItem(fi.Name, value);
// 既然是反序列得到的值直接赋值就行了。这里不需要SetItem因为SetItem会设置脏数据在实体对象很多时>100w造成巨大的内存开销
this[fi.Name] = value;
}
return true;

View File

@ -215,9 +215,9 @@ public static class EntityExtension
if (session.Dal.SupportBatch && list2.Count() > 1)
{
// 根据是否来自数据库,拆分为两组
var ts = Split(list2);
list2 = ts.Item1;
rs += BatchSave(session, ts.Item2.Valid(true));
var (updates, others) = Split(list2);
list2 = updates;
rs += BatchSave(session, others.Valid(true), null);
}
return rs + DoAction(list2, useTransition, e => e.Save(), session);
@ -243,15 +243,19 @@ public static class EntityExtension
if (session.Dal.SupportBatch && list2.Count() > 1)
{
// 根据是否来自数据库,拆分为两组
var ts = Split(list2);
list2 = ts.Item1;
rs += BatchSave(session, ts.Item2);
var (updates, others) = Split(list2);
list2 = updates;
rs += BatchSave(session, others, null);
}
return rs + DoAction(list2, useTransition, e => e.SaveWithoutValid(), session);
}
private static Tuple<IList<T>, IList<T>> Split<T>(IEnumerable<T> list) where T : IEntity
/// <summary>拆分为来自数据库的更新和其它的Upsert</summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <returns></returns>
private static (IList<T> updates, IList<T> others) Split<T>(IEnumerable<T> list) where T : IEntity
{
var updates = new List<T>();
var others = new List<T>();
@ -263,10 +267,10 @@ public static class EntityExtension
others.Add(item);
}
return new Tuple<IList<T>, IList<T>>(updates, others);
return (updates, others);
}
private static Int32 BatchSave<T>(IEntitySession session, IEnumerable<T> list) where T : IEntity
private static Int32 BatchSave<T>(IEntitySession session, IEnumerable<T> list, BatchOption? option) where T : IEntity
{
// 没有其它唯一索引,且主键为空时,走批量插入
var rs = 0;
@ -289,18 +293,18 @@ public static class EntityExtension
}
list = upserts;
if (inserts.Count > 0) rs += BatchInsert(inserts, option: null, session);
if (inserts.Count > 0) rs += BatchInsert(inserts, option, session);
if (updates.Count > 0)
{
// 只有Oracle支持批量Update
if (session.Dal.DbType == DatabaseType.Oracle)
rs += BatchUpdate(updates, null, session);
rs += BatchUpdate(updates, option, session);
else
upserts.AddRange(upserts);
}
}
if (list.Any()) rs += BatchUpsert(list, null, session);
if (list.Any()) rs += BatchUpsert(list, option, session);
return rs;
}
@ -1408,7 +1412,8 @@ public static class EntityExtension
for (var i = 0; i < fields.Length && i < line.Length; i++)
{
var fi = fields[i];
if (fi != null && !line[i].IsNullOrEmpty()) entity.SetItem(fi.Name, line[i].ChangeType(fi.Type));
//if (fi != null && !line[i].IsNullOrEmpty()) entity.SetItem(fi.Name, line[i].ChangeType(fi.Type));
if (fi != null && !line[i].IsNullOrEmpty()) entity[fi.Name] = line[i].ChangeType(fi.Type);
}
yield return entity;

View File

@ -10,6 +10,7 @@ using NewLife.Caching;
using NewLife.Data;
using NewLife.Log;
using NewLife.Reflection;
using XCode.Model;
using XCode.Transform;
namespace XCode.Membership;
@ -1060,7 +1061,11 @@ public partial class Area : Entity<Area>
}
}
bs.Save(true);
//Meta.Factory.FullInsert = true;
//count = bs.Save(true);
count = bs.BatchUpsert(new BatchOption { FullInsert = true });
XTrace.WriteLine("合并三级地址成功:{0:n0}", count);
return count;
}
@ -1076,6 +1081,7 @@ public partial class Area : Entity<Area>
// 一次性加载四级地址
var rs = FindAll(_.ID < 99_99_99_999);
var bs = new List<Area>();
var count = 0;
foreach (var r in list)
@ -1097,7 +1103,8 @@ public partial class Area : Entity<Area>
r.CreateTime = DateTime.Now;
r.UpdateTime = DateTime.Now;
r.Valid(DataMethod.Insert);
r.SaveAsync();
//r.SaveAsync();
bs.Add(r);
count++;
}
@ -1121,13 +1128,20 @@ public partial class Area : Entity<Area>
XTrace.Log.Debug(re.Dirtys.Join(",", e => $"{e}={r2[e]}"));
r2.SaveAsync();
//r2.SaveAsync();
bs.Add(r2);
count++;
}
}
}
//Meta.Factory.FullInsert = true;
//count = bs.Save(true);
count = bs.BatchUpsert(new BatchOption { FullInsert = true });
XTrace.WriteLine("合并四级地址成功:{0:n0}", count);
return count;
}

View File

@ -86,7 +86,12 @@ public class UserModule : EntityModule
// 新增时如果没有当前用户,尝试使用环境变量中的用户名
if (user == null && method == DataMethod.Insert)
user = new User { Name = Environment.UserName };
{
// 如果用户名为空或者是root或Administrator则使用计算机名
var name = Environment.UserName;
if (name.IsNullOrEmpty() || name.EqualIgnoreCase("root", "Administrator")) name = Environment.MachineName;
user = new User { Name = name };
}
if (user != null)
{

View File

@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using NewLife;
using NewLife.Http;
using NewLife.IP;
@ -199,7 +200,7 @@ public class AreaTests
}
[Fact]
public async void Download()
public async Task Download()
{
//var url = "http://www.mca.gov.cn/article/sj/xzqh/2020/2020/2020092500801.html";
var url = "http://x.newlifex.com/202301xzqh.html";
@ -214,7 +215,7 @@ public class AreaTests
}
[Fact]
public async void Download2024()
public async Task Download2024()
{
//var url = "http://www.mca.gov.cn/article/sj/xzqh/2020/2020/2020092500801.html";
//var url = "http://x.newlifex.com/202301xzqh.html";
@ -242,6 +243,7 @@ public class AreaTests
var rs = Parse(txt).ToList();
Assert.NotNull(rs);
Assert.True(rs.Count > 3000);
Assert.Equal(3208, rs.Count);
}
[Fact]
@ -257,6 +259,7 @@ public class AreaTests
var rs = Parse(txt).ToList();
Assert.NotNull(rs);
Assert.True(rs.Count > 3000);
Assert.Equal(3213, rs.Count);
}
//[Fact]
@ -320,7 +323,7 @@ public class AreaTests
[TestOrder(0)]
[Fact]
public async void Import()
public async Task Import()
{
Area.Meta.Session.Dal.Db.ShowSQL = false;
@ -337,10 +340,12 @@ public class AreaTests
Area.Meta.Session.Truncate();
var rs = Area.Import(file, true, 3, false);
Assert.Equal(3639, rs);
Assert.Equal(3639, Area.FindCount());
Area.Meta.Session.Truncate();
rs = Area.Import(file, true, 4, true);
Assert.Equal(46533, rs);
Assert.Equal(46533, Area.FindCount());
}
Area.Meta.Session.Dal.Db.ShowSQL = true;