Skip to content

Commit

Permalink
FindByKey与FindByKeyForEdit支持key传入IModel,其中带有主键和分表字段,专用于解决分表字段不是主键的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Jul 28, 2024
1 parent 62a95a7 commit c396a48
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 127 deletions.
140 changes: 32 additions & 108 deletions XCode/Entity/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -573,51 +573,12 @@ public virtual Boolean Exist(Boolean isNew, params String[] names)
/// <returns></returns>
public static TEntity? Find(String name, Object value, String selects) => Find([name], [value], selects);

/// <summary>根据属性列表以及对应的值列表,查找单个实体</summary>
/// <param name="names">属性名称集合</param>
/// <param name="values">属性值集合</param>
/// <returns></returns>
public static TEntity? Find(String[] names, Object[] values)
{
if (names == null || names.Length == 0) throw new ArgumentNullException(nameof(names));
if (values == null || values.Length == 0) throw new ArgumentNullException(nameof(values));

var exp = new WhereExpression();
// 判断自增和主键
if (names.Length == 1)
{
var field = Meta.Table.FindByName(names[0]);
if ((field as FieldItem) != null && (field.IsIdentity || field.PrimaryKey))
{
// 唯一键为自增且参数小于等于0时,返回空
if (Helper.IsNullKey(values[0], field.Type)) return null;

exp &= field == values[0];
return FindUnique(exp);
}
}

for (var i = 0; i < names.Length; i++)
{
var fi = Meta.Table.FindByName(names[i]);
if (ReferenceEquals(fi, null)) throw new ArgumentOutOfRangeException(nameof(names), $"{names[i]} not found");

exp &= fi == values[i];
}

// 判断唯一索引,唯一索引也不需要分页
var di = Meta.Table.DataTable.GetIndex(names);
if (di != null && di.Unique) return FindUnique(exp);

return Find(exp);
}

/// <summary>根据属性列表以及对应的值列表,查找单个实体</summary>
/// <param name="names">属性名称集合</param>
/// <param name="values">属性值集合</param>
/// <param name="selects">查询列,默认null表示所有字段</param>
/// <returns></returns>
public static TEntity? Find(String[] names, Object[] values, String selects)
public static TEntity? Find(String[] names, Object[] values, String? selects = null)
{
if (names == null || names.Length == 0) throw new ArgumentNullException(nameof(names));
if (values == null || values.Length == 0) throw new ArgumentNullException(nameof(values));
Expand Down Expand Up @@ -652,48 +613,6 @@ public virtual Boolean Exist(Boolean isNew, params String[] names)
return Find(exp, selects);
}

/// <summary>根据条件查找唯一的单个实体</summary>
/// 根据条件查找唯一的单个实体,因为是唯一的,所以不需要分页和排序。
/// 如果不确定是否唯一,一定不要调用该方法,否则会返回大量的数据。
/// <remarks>
/// </remarks>
/// <param name="where">查询条件</param>
/// <returns></returns>
private static TEntity? FindUnique(Expression where)
{
var session = Meta.Session;
var db = session.Dal.Db;
var ps = db.UseParameter ? new Dictionary<String, Object>() : null;
var wh = where?.GetString(db, ps);

var builder = new SelectBuilder
{
Table = session.FormatedTableName,
// 谨记:某些项目中可能在where中使用了GroupBy,在分页时可能报错
Where = wh

};

// 使用默认选择列
if (builder.Column.IsNullOrEmpty()) builder.Column = Meta.Factory.Selects;

// 提取参数
builder = FixParam(builder, ps);

var list = LoadData(session.Query(builder, 0, 0));
//var list = session.Query(builder, 0, 0, LoadData);
if (list == null || list.Count <= 0) return null;

// 如果正在使用单对象缓存,则批量进入
LoadSingleCache(list);

if (list.Count > 1 && DAL.Debug)
{
DAL.WriteLog("调用FindUnique(\"{0}\")不合理,只有返回唯一记录的查询条件才允许调用!", wh);
}
return list[0];
}

/// <summary>根据条件查找唯一的单个实体</summary>
/// 根据条件查找唯一的单个实体,因为是唯一的,所以不需要分页和排序。
/// 如果不确定是否唯一,一定不要调用该方法,否则会返回大量的数据。
Expand All @@ -702,7 +621,7 @@ public virtual Boolean Exist(Boolean isNew, params String[] names)
/// <param name="where">查询条件</param>
/// <param name="selects">查询列,默认null表示所有字段</param>
/// <returns></returns>
private static TEntity? FindUnique(Expression where, String selects)
private static TEntity? FindUnique(Expression where, String? selects = null)
{
var session = Meta.Session;
var db = session.Dal.Db;
Expand Down Expand Up @@ -750,22 +669,13 @@ public virtual Boolean Exist(Boolean isNew, params String[] names)
/// <summary>根据条件查找单个实体</summary>
/// <param name="where">查询条件</param>
/// <returns></returns>
public static TEntity? Find(Expression where)
{
var max = 1;

// 优待主键查询
if (where is FieldExpression fe && fe.Field != null && fe.Field.PrimaryKey) max = 0;

var list = FindAll(where, null, null, 0, max);
return list.Count <= 0 ? null : list[0];
}
public static TEntity? Find(Expression where) => Find(where, null);

/// <summary>根据条件查找单个实体</summary>
/// <param name="where">查询条件</param>
/// <param name="selects">查询列,默认null表示所有字段</param>
/// <returns></returns>
public static TEntity? Find(Expression where, String selects)
public static TEntity? Find(Expression where, String? selects)
{
var max = 1;

Expand All @@ -780,28 +690,35 @@ public virtual Boolean Exist(Boolean isNew, params String[] names)
/// <param name="key">唯一主键的值</param>
/// <param name="selects">查询列,默认null表示所有字段</param>
/// <returns></returns>
public static TEntity? FindByKey(Object key, String selects)
public static TEntity? FindByKey(Object key, String? selects)
{
var field = Meta.Unique ?? throw new ArgumentNullException(nameof(Meta.Unique), "FindByKey方法要求" + typeof(TEntity).FullName + "有唯一主键!");

// 查询时可能传入IModel,为了分表查询,主要解决分表字段不是主键的场景
var model = key as IModel;
if (model != null) key = model[field.Name]!;

// 唯一键为自增且参数小于等于0时,返回空
if (Helper.IsNullKey(key, field.Type)) return null;

return Find(field.Name, key, selects);
if (Meta.InShard) return Find(field.Name, key);

// 自动分库分表
if (model == null)
{
model = new TEntity();
model[field.Name] = key;
}
using var split = Meta.CreateShard(model);

// 此外,一律返回 查找值,即使可能是空。而绝不能在找不到数据的情况下给它返回空,因为可能是找不到数据而已,而返回新实例会导致前端以为这里是新增数据
return Find(field.Name, key);
}

/// <summary>根据主键查找单个实体</summary>
/// <param name="key">唯一主键的值</param>
/// <returns></returns>
public static TEntity? FindByKey(Object key)
{
var field = Meta.Unique ?? throw new ArgumentNullException(nameof(Meta.Unique), "FindByKey方法要求" + typeof(TEntity).FullName + "有唯一主键!");

// 唯一键为自增且参数小于等于0时,返回空
if (Helper.IsNullKey(key, field.Type)) return null;

return Find(field.Name, key);
}
public static TEntity? FindByKey(Object key) => FindByKey(key, null);

/// <summary>根据主键查询一个实体对象用于表单编辑</summary>
/// <param name="key">唯一主键的值</param>
Expand All @@ -810,6 +727,10 @@ public virtual Boolean Exist(Boolean isNew, params String[] names)
{
var field = Meta.Unique ?? throw new ArgumentNullException("Meta.Unique", "FindByKeyForEdit方法要求该表有唯一主键!");

// 查询时可能传入IModel,为了分表查询,主要解决分表字段不是主键的场景
var model = key as IModel;
if (model != null) key = model[field.Name]!;

// 参数为空时,返回新实例
if (key == null) return Meta.Factory.Create(true) as TEntity;

Expand All @@ -831,9 +752,12 @@ public virtual Boolean Exist(Boolean isNew, params String[] names)
else
{
// 自动分库分表
var keyEntity = new TEntity();
keyEntity[field.Name] = key;
using var split = Meta.CreateShard(keyEntity);
if (model == null)
{
model = new TEntity();
model[field.Name] = key;
}
using var split = Meta.CreateShard(model);

// 此外,一律返回 查找值,即使可能是空。而绝不能在找不到数据的情况下给它返回空,因为可能是找不到数据而已,而返回新实例会导致前端以为这里是新增数据
entity = Find(field.Name, key);
Expand Down
18 changes: 9 additions & 9 deletions XCode/Entity/Entity_Meta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,15 @@ void Reset()
/// <returns></returns>
public static IDisposable CreateSplit(String connName, String tableName) => new SplitPackge(connName, tableName);

/// <summary>针对实体对象自动分库分表</summary>
/// <param name="entity"></param>
/// <returns></returns>
public static IDisposable? CreateShard(TEntity entity)
{
// 使用自动分表分库策略
var model = ShardPolicy?.Shard(entity);
return model != null ? new SplitPackge(model.ConnName, model.TableName) : null;
}
///// <summary>针对实体对象自动分库分表</summary>
///// <param name="entity"></param>
///// <returns></returns>
//public static IDisposable? CreateShard(TEntity entity)
//{
// // 使用自动分表分库策略
// var model = ShardPolicy?.Shard(entity);
// return model != null ? new SplitPackge(model.ConnName, model.TableName) : null;
//}

/// <summary>为实体对象、时间、雪花Id等计算分表分库</summary>
/// <param name="value"></param>
Expand Down
8 changes: 4 additions & 4 deletions XCode/Entity/Entity_Operate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,10 @@ public DefaultEntityFactory()
/// <returns></returns>
public virtual IDisposable CreateSplit(String connName, String tableName) => Meta.CreateSplit(connName, tableName);

/// <summary>针对实体对象自动分库分表</summary>
/// <param name="entity"></param>
/// <returns></returns>
public virtual IDisposable? CreateShard(IEntity entity) => Meta.CreateShard((entity as TEntity)!);
///// <summary>针对实体对象自动分库分表</summary>
///// <param name="entity"></param>
///// <returns></returns>
//public virtual IDisposable? CreateShard(IEntity entity) => Meta.CreateShard((entity as TEntity)!);

/// <summary>为实体对象、时间、雪花Id等计算分表分库</summary>
/// <param name="value"></param>
Expand Down
8 changes: 4 additions & 4 deletions XCode/Entity/IEntityOperate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ public interface IEntityFactory
/// <returns></returns>
IDisposable CreateSplit(String connName, String tableName);

/// <summary>针对实体对象自动分库分表</summary>
/// <param name="entity"></param>
/// <returns></returns>
IDisposable? CreateShard(IEntity entity);
///// <summary>针对实体对象自动分库分表</summary>
///// <param name="entity"></param>
///// <returns></returns>
//IDisposable? CreateShard(IEntity entity);

/// <summary>为实体对象、时间、雪花Id等计算分表分库</summary>
/// <param name="value"></param>
Expand Down
5 changes: 3 additions & 2 deletions XCode/Shards/TimeShardPolicy.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NewLife;
using NewLife.Data;
using XCode.Configuration;
using XCode.Statistics;

Expand Down Expand Up @@ -62,7 +63,7 @@ public TimeShardPolicy(String fieldName, IEntityFactory factory)
/// <returns></returns>
public virtual ShardModel? Shard(Object value)
{
if (value is IEntity entity) return Shard(entity);
if (value is IModel entity) return Shard(entity);
if (value is DateTime dt) return Shard(dt);
if (value is Int64 id)
{
Expand All @@ -80,7 +81,7 @@ public TimeShardPolicy(String fieldName, IEntityFactory factory)
/// <summary>为实体对象计算分表分库</summary>
/// <param name="entity"></param>
/// <returns></returns>
public virtual ShardModel? Shard(IEntity entity)
public virtual ShardModel? Shard(IModel entity)
{
var fi = GetField();
if (fi == null) throw new XCodeException("分表策略要求指定时间字段!");
Expand Down

0 comments on commit c396a48

Please sign in to comment.