196 lines
7.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using FreeSql.Extensions.EntityUtil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql
{
public abstract partial class BaseRepository<TEntity> : IBaseRepository<TEntity>
where TEntity : class
{
internal RepositoryDbContext _dbPriv; //这个不能私有化,有地方需要反射获取它
internal RepositoryDbContext _db => _dbPriv ?? (_dbPriv = new RepositoryDbContext(OrmOriginal, this));
internal RepositoryDbSet<TEntity> _dbsetPriv;
internal RepositoryDbSet<TEntity> _dbset => _dbsetPriv ?? (_dbsetPriv = _db.Set<TEntity>() as RepositoryDbSet<TEntity>);
public IDataFilter<TEntity> DataFilter { get; } = new DataFilter<TEntity>();
internal Func<string, string> AsTableValueInternal { get; private set; }
internal Func<Type, string, string> AsTableSelectValueInternal { get; private set; }
protected void ApplyDataFilter(string name, Expression<Func<TEntity, bool>> exp) => DataFilter.Apply(name, exp);
protected BaseRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter, Func<string, string> asTable = null)
{
_ormScoped = DbContextScopedFreeSql.Create(fsql, () => _db, () => UnitOfWork);
DataFilterUtil.SetRepositoryDataFilter(this, null);
DataFilter.Apply("", filter);
AsTable(asTable);
}
~BaseRepository() => this.Dispose();
int _disposeCounter;
public void Dispose()
{
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
try
{
_dbsetPriv?.Dispose();
_dbPriv?.Dispose();
this.DataFilter.Dispose();
}
finally
{
GC.SuppressFinalize(this);
}
}
public Type EntityType => _dbsetPriv?.EntityType ?? typeof(TEntity);
public void AsType(Type entityType) => _dbset.AsType(entityType);
public void AsTable(Func<string, string> rule)
{
AsTableValueInternal = rule;
AsTableSelectValueInternal = rule == null ? null : new Func<Type, string, string>((a, b) => a == EntityType ? rule(b) : null);
}
public DbContextOptions DbContextOptions { get => _db.Options; set => _db.Options = value; }
internal DbContextScopedFreeSql _ormScoped;
internal IFreeSql OrmOriginal => _ormScoped?._originalFsql;
public IFreeSql Orm => _ormScoped;
IUnitOfWork _unitOfWork;
public IUnitOfWork UnitOfWork
{
set
{
_unitOfWork = value;
if (_dbsetPriv != null) _dbsetPriv._uow = _unitOfWork; //防止 dbset 对象已经存在,再次设置 UnitOfWork 无法生效,所以作此判断重新设置
if (_dbPriv != null) _dbPriv.UnitOfWork = _unitOfWork;
}
get => _unitOfWork;
}
public IUpdate<TEntity> UpdateDiy => _dbset.OrmUpdateInternal(null);
public virtual ISelect<TEntity> Select => _dbset.OrmSelectInternal(null);
public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => Select.Where(exp);
public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => Select.WhereIf(condition, exp);
public virtual int Delete(Expression<Func<TEntity, bool>> predicate)
{
var delete = _dbset.OrmDeleteInternal(null).Where(predicate);
var sql = delete.ToSql();
var affrows = delete.ExecuteAffrows();
_db._entityChangeReport.Add(new DbContext.EntityChangeReport.ChangeInfo { Object = sql, Type = DbContext.EntityChangeType.SqlRaw });
return affrows;
}
public virtual int Delete(TEntity entity)
{
_dbset.Remove(entity);
return _db.SaveChanges();
}
public virtual int Delete(IEnumerable<TEntity> entitys)
{
_dbset.RemoveRange(entitys);
return _db.SaveChanges();
}
public virtual TEntity Insert(TEntity entity)
{
_dbset.Add(entity);
_db.SaveChanges();
return entity;
}
public virtual List<TEntity> Insert(IEnumerable<TEntity> entitys)
{
_dbset.AddRange(entitys);
_db.SaveChanges();
return entitys.ToList();
}
public virtual int Update(TEntity entity)
{
_dbset.Update(entity);
return _db.SaveChanges();
}
public virtual int Update(IEnumerable<TEntity> entitys)
{
_dbset.UpdateRange(entitys);
return _db.SaveChanges();
}
public void Attach(TEntity data) => _dbset.Attach(data);
public void Attach(IEnumerable<TEntity> data) => _dbset.AttachRange(data);
public IBaseRepository<TEntity> AttachOnlyPrimary(TEntity data)
{
_dbset.AttachOnlyPrimary(data);
return this;
}
public void FlushState() => _dbset.FlushState();
public virtual TEntity InsertOrUpdate(TEntity entity)
{
_dbset.AddOrUpdate(entity);
_db.SaveChanges();
return entity;
}
public void SaveMany(TEntity entity, string propertyName)
{
_dbset.SaveMany(entity, propertyName);
_db.SaveChanges();
}
public void BeginEdit(List<TEntity> data) => _dbset.BeginEdit(data);
public int EndEdit(List<TEntity> data = null)
{
_db.FlushCommand();
if (UnitOfWork?.GetOrBeginTransaction(true) == null && _db.OrmOriginal.Ado.TransactionCurrentThread == null)
{
int affrows = 0;
IUnitOfWork olduow = UnitOfWork;
UnitOfWork = new UnitOfWork(_db.OrmOriginal);
try
{
affrows = _dbset.EndEdit(data);
UnitOfWork.Commit();
}
catch
{
UnitOfWork.Rollback();
throw;
}
finally
{
UnitOfWork.Dispose();
UnitOfWork = olduow;
}
return affrows;
}
return _dbset.EndEdit(data);
}
}
public abstract partial class BaseRepository<TEntity, TKey> : BaseRepository<TEntity>, IBaseRepository<TEntity, TKey>
where TEntity : class
{
public BaseRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter, Func<string, string> asTable = null) : base(fsql, filter, asTable) { }
TEntity CheckTKeyAndReturnIdEntity(TKey id)
{
var tb = _db.OrmOriginal.CodeFirst.GetTableByEntity(EntityType);
if (tb.Primarys.Length != 1) throw new Exception($"实体类型 {EntityType.Name} 主键数量不为 1无法使用该方法");
if (tb.Primarys[0].CsType.NullableTypeOrThis() != typeof(TKey).NullableTypeOrThis()) throw new Exception($"实体类型 {EntityType.Name} 主键类型不为 {typeof(TKey).FullName},无法使用该方法");
var obj = Activator.CreateInstance(tb.Type);
_db.OrmOriginal.SetEntityValueWithPropertyName(tb.Type, obj, tb.Primarys[0].CsName, id);
var ret = obj as TEntity;
if (ret == null) throw new Exception($"实体类型 {EntityType.Name} 无法转换为 {typeof(TEntity).Name},无法使用该方法");
return ret;
}
public virtual int Delete(TKey id) => Delete(CheckTKeyAndReturnIdEntity(id));
public virtual TEntity Find(TKey id) => Select.WhereDynamic(CheckTKeyAndReturnIdEntity(id)).ToOne();
public TEntity Get(TKey id) => Find(id);
}
}