EF架构~基于EF数据层的实现
之前写过关于实现一个完整的EF架构的文章,文章的阅读量也是满大的,自己很欣慰,但是,那篇文章是我2011年写的,所以,技术有些不成熟,所以今天把我的2014年写的EF底层架构公开一下,这个架构比2011年的有了很大程度的提高,主要在接口规范,查询规范上,并引入了排序功能,两步对完善了EF对数据的批量操作,可以说,这次的架构是很有看点的。
一 一个基础操作接口
/// <summary>
/// 基础的数据操作规范
/// 与ORM架构无关
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public interface IRepository<TEntity>
where TEntity : class
{
/// <summary>
/// 设定数据上下文,它一般由构架方法注入
/// </summary>
/// <param name="unitOfWork"></param>
void SetDbContext(IUnitOfWork unitOfWork); /// <summary>
/// 添加实体并提交到数据服务器
/// </summary>
/// <param name="item">Item to add to repository</param>
void Insert(TEntity item); /// <summary>
/// 移除实体并提交到数据服务器
/// 如果表存在约束,需要先删除子表信息
/// </summary>
/// <param name="item">Item to delete</param>
void Delete(TEntity item); /// <summary>
/// 修改实体并提交到数据服务器
/// </summary>
/// <param name="item"></param>
void Update(TEntity item); /// <summary>
/// 得到指定的实体集合(延时结果集)
/// Get all elements of type {T} in repository
/// </summary>
/// <returns>List of selected elements</returns>
IQueryable<TEntity> GetModel(); /// <summary>
/// 根据主键得到实体
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
TEntity Find(params object[] id);
}
二 一个扩展操作接口
/// <summary>
/// 扩展的Repository操作规范
/// </summary>
public interface IExtensionRepository<TEntity> :
IRepository<TEntity>,
IOrderableRepository<TEntity>
where TEntity : class
{
/// <summary>
/// 添加集合[集合数目不大时用此方法,超大集合使用BulkInsert]
/// </summary>
/// <param name="item"></param>
void Insert(IEnumerable<TEntity> item); /// <summary>
/// 修改集合[集合数目不大时用此方法,超大集合使用BulkUpdate]
/// </summary>
/// <param name="item"></param>
void Update(IEnumerable<TEntity> item); /// <summary>
/// 删除集合[集合数目不大时用此方法,超大集合使用批量删除]
/// </summary>
/// <param name="item"></param>
void Delete(IEnumerable<TEntity> item); /// <summary>
/// 扩展更新方法,只对EF支持
/// 注意本方法不能和GetModel()一起使用,它的表主键可以通过post或get方式获取
/// </summary>
/// <param name="entity"></param>
void Update<T>(Expression<Action<T>> entity) where T : class; /// <summary>
/// 根据指定lambda表达式,得到延时结果集
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate); /// <summary>
/// 根据指定lambda表达式,得到第一个实体
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
TEntity Find(Expression<Func<TEntity, bool>> predicate); /// <summary>
/// 批量添加,添加之前可以去除自增属性,默认不去除
/// </summary>
/// <param name="item"></param>
/// <param name="isRemoveIdentity"></param>
void BulkInsert(IEnumerable<TEntity> item, bool isRemoveIdentity); /// <summary>
/// 批量添加
/// </summary>
/// <param name="item"></param>
void BulkInsert(IEnumerable<TEntity> item); /// <summary>
/// 批量更新
/// </summary>
/// <param name="item"></param>
void BulkUpdate(IEnumerable<TEntity> item, params string[] fieldParams); /// <summary>
/// 批量删除
/// </summary>
/// <param name="item"></param>
void BulkDelete(IEnumerable<TEntity> item); }
三 一个排序操作接口
/// <summary>
/// 提供排序功能的规范
/// </summary>
public interface IOrderableRepository<TEntity> where TEntity : class
{
/// <summary>
/// 带排序的结果集
/// </summary>
/// <param name="orderBy"></param>
/// <returns></returns>
IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy); /// <summary>
/// 根据指定lambda表达式和排序方式,得到延时结果集
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, Expression<Func<TEntity, bool>> predicate);
}
四 基于ef架构的规约查询接口
/// <summary>
/// EF底层构架,关于规约功能的仓储接口
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public interface ISpecificationRepository<TEntity> :
IExtensionRepository<TEntity>
where TEntity : class
{
/// <summary>
/// 根据指定规约,得到延时结果集
/// </summary>
/// <param name="specification"></param>
/// <returns></returns>
IQueryable<TEntity> GetModel(ISpecification<TEntity> specification); /// <summary>
/// 根据指定规约,得到第一个实体
/// </summary>
/// <param name="specification"></param>
/// <returns></returns>
TEntity Find(ISpecification<TEntity> specification); /// <summary>
/// 带排序功能的,根据指定规约,得到结果集
/// </summary>
/// <param name="orderBy"></param>
/// <param name="specification"></param>
/// <returns></returns>
IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, EntityFrameworks.Entity.Core.Specification.ISpecification<TEntity> specification); /// <summary>
/// 保存之后触发
/// Occurs after data saved
/// </summary>
event Action<SavedEventArgs> AfterSaved; /// <summary>
/// 保存之前触发
/// Occurs before data saved
/// </summary>
event Action<SavedEventArgs> BeforeSaved;
}
五 基于工作单元的标识接口
/// <summary>
/// 数据上下文标识接口,它对于业务层应该是公开的
/// 它对于实现上下文的方法,它并不关心,可以是linq2sql,ef,ado.net,nhibernate,memory,nosql等
/// </summary>
public interface IUnitOfWork
{
}
六 基于ef的DbContext上下文的仓储的实现
/// <summary>
/// DbContext上下文仓储功能类,领域上下文可以直接继承它
/// 生命周期:数据上下文的生命周期为一个HTTP请求的结束
/// 相关说明:
/// 1 领域对象使用声明IRepository和IExtensionRepository接口得到不同的操作规范
/// 2 可以直接为上下注入Action<string>的委托实例,用来记录savechanges产生的异常
/// 3 可以订阅BeforeSaved和AfterSaved两个事件,用来在方法提交前与提交后实现代码注入
/// 4 所有领域db上下文都要继承iUnitWork接口,用来实现工作单元,这对于提升程序性能与为重要
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public class DbContextRepository<TEntity> :
ISpecificationRepository<TEntity>
where TEntity : class
{
#region Constructors public DbContextRepository(IUnitOfWork db, Action<string> logger)
{
UnitWork = db;
Db = (DbContext)db;
Logger = logger;
((IObjectContextAdapter)Db).ObjectContext.CommandTimeout = ;
} public DbContextRepository(IUnitOfWork db)
: this(db, null)
{ }
#endregion #region Properties
/// <summary>
/// 数据上下文
/// </summary>
protected DbContext Db { get; private set; } /// <summary>
/// 工作单元上下文,子类可以直接使用它
/// </summary>
protected IUnitOfWork UnitWork { get; set; } /// <summary>
/// Action委托事例,在派生类可以操作它
/// </summary>
protected Action<string> Logger { get; private set; }
#endregion #region Fields
/// <summary>
/// 数据总数
/// </summary>
int _dataTotalCount = ; /// <summary>
/// 数据总页数
/// </summary>
int _dataTotalPages = ; /// <summary>
/// 数据页面大小(每次向数据库提交的记录数)
/// </summary>
private const int DataPageSize = ; #endregion #region Delegates & Event
/// <summary>
/// 保存之后
/// </summary>
public event Action<SavedEventArgs> AfterSaved;
/// <summary>
/// 保存之前
/// </summary>
public event Action<SavedEventArgs> BeforeSaved;
#endregion #region IRepository<TEntity> 成员 public void SetDbContext(IUnitOfWork unitOfWork)
{
this.Db = (DbContext)unitOfWork;
this.UnitWork = unitOfWork;
} public virtual void Insert(TEntity item)
{
OnBeforeSaved(new SavedEventArgs(item, SaveAction.Insert));
Db.Entry<TEntity>(item);
Db.Set<TEntity>().Add(item);
this.SaveChanges();
OnAfterSaved(new SavedEventArgs(item, SaveAction.Insert));
} public virtual void Delete(TEntity item)
{
OnBeforeSaved(new SavedEventArgs(item, SaveAction.Delete));
Db.Set<TEntity>().Attach(item);
Db.Set<TEntity>().Remove(item);
this.SaveChanges();
OnAfterSaved(new SavedEventArgs(item, SaveAction.Delete));
} public virtual void Update(TEntity item)
{
OnBeforeSaved(new SavedEventArgs(item, SaveAction.Update));
Db.Set<TEntity>().Attach(item);
Db.Entry(item).State = EntityState.Modified;
try
{
this.SaveChanges();
}
catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
{ ((IObjectContextAdapter)Db).ObjectContext.Refresh(RefreshMode.ClientWins, item);
this.SaveChanges();
} OnAfterSaved(new SavedEventArgs(item, SaveAction.Update));
} /// <summary>
/// 子类在实现时,可以重写,加一些状态过滤
/// </summary>
/// <returns></returns>
public virtual IQueryable<TEntity> GetModel()
{
// return Db.Set<TEntity>().AsNoTracking();//对象无法自动添加到上下文中,因为它是使用 NoTracking 合并选项检索的。请在定义此关系之前,将该实体显式附加到 ObjectContext。
return Db.Set<TEntity>();////ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
}
/// <summary>
/// 得到原生态结果集
/// </summary>
/// <returns></returns>
public IQueryable<TEntity> GetEntities()
{
return Db.Set<TEntity>();
}
#endregion #region IExtensionRepository<TEntity> 成员 public virtual void Insert(IEnumerable<TEntity> item)
{
item.ToList().ForEach(i =>
{
Db.Entry<TEntity>(i);
Db.Set<TEntity>().Add(i);
});
this.SaveChanges();
} public virtual void Delete(IEnumerable<TEntity> item)
{
item.ToList().ForEach(i =>
{
Db.Set<TEntity>().Attach(i);
Db.Set<TEntity>().Remove(i);
});
this.SaveChanges();
} public virtual void Update(IEnumerable<TEntity> item)
{
item.ToList().ForEach(i =>
{
Db.Set<TEntity>().Attach(i);
Db.Entry(i).State = EntityState.Modified;
});
try
{
this.SaveChanges();
}
catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
{ ((IObjectContextAdapter)Db).ObjectContext.Refresh(RefreshMode.ClientWins, item);
this.SaveChanges();
}
} public void Update<T>(Expression<Action<T>> entity) where T : class
{ T newEntity = typeof(T).GetConstructor(Type.EmptyTypes).Invoke(null) as T;//建立指定类型的实例
List<string> propertyNameList = new List<string>();
MemberInitExpression param = entity.Body as MemberInitExpression;
foreach (var item in param.Bindings)
{
string propertyName = item.Member.Name;
object propertyValue;
var memberAssignment = item as MemberAssignment;
if (memberAssignment.Expression.NodeType == ExpressionType.Constant)
{
propertyValue = (memberAssignment.Expression as ConstantExpression).Value;
}
else
{
propertyValue = Expression.Lambda(memberAssignment.Expression, null).Compile().DynamicInvoke();
}
typeof(T).GetProperty(propertyName).SetValue(newEntity, propertyValue, null);
propertyNameList.Add(propertyName);
} try
{
Db.Set<T>().Attach(newEntity);
}
catch (Exception)
{
throw new Exception("本方法不能和GetModel()一起使用,请使用Update(TEntity entity)方法");
} Db.Configuration.ValidateOnSaveEnabled = false;
var ObjectStateEntry = ((IObjectContextAdapter)Db).ObjectContext.ObjectStateManager.GetObjectStateEntry(newEntity);
propertyNameList.ForEach(x => ObjectStateEntry.SetModifiedProperty(x.Trim())); try
{
this.SaveChanges(); }
catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
{ ((IObjectContextAdapter)Db).ObjectContext.Refresh(RefreshMode.ClientWins, newEntity);
this.SaveChanges();
}
} public TEntity Find(params object[] id)
{
return Db.Set<TEntity>().Find(id);
} public IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate)
{
return GetModel().Where(predicate);
} public TEntity Find(Expression<Func<TEntity, bool>> predicate)
{
return GetModel(predicate).FirstOrDefault();
} public void BulkInsert(IEnumerable<TEntity> item)
{
BulkInsert(item, false);
} public void BulkInsert(IEnumerable<TEntity> item, bool isRemoveIdentity)
{
string startTag = "", endTag = "";
if (isRemoveIdentity)
{
startTag = "SET IDENTITY_INSERT " + typeof(TEntity).Name + " ON;";
endTag = "SET IDENTITY_INSERT " + typeof(TEntity).Name + " OFF;";
}
DataPageProcess(item, (currentItems) =>
{
((IObjectContextAdapter)Db).ObjectContext.CommandTimeout = ;//永不超时
Db.Database.ExecuteSqlCommand(startTag
+ DoSql(currentItems, SqlType.Insert)
+ endTag);
});
} public void BulkDelete(IEnumerable<TEntity> item)
{
DataPageProcess(item, (currentItems) =>
{
((IObjectContextAdapter)Db).ObjectContext.CommandTimeout = ;//永不超时
Db.Database.ExecuteSqlCommand(DoSql(currentItems, SqlType.Delete));
});
} public void BulkUpdate(IEnumerable<TEntity> item, params string[] fieldParams)
{
DataPageProcess(item, (currentItems) =>
{
((IObjectContextAdapter)Db).ObjectContext.CommandTimeout = ;//永不超时
Db.Database.ExecuteSqlCommand(DoSql(currentItems, SqlType.Update, fieldParams));
});
} #endregion #region ISpecificationRepository<TEntity> 成员 public TEntity Find(ISpecification<TEntity> specification)
{
return GetModel(specification).FirstOrDefault();
} public IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, ISpecification<TEntity> specification)
{
var linq = new Orderable<TEntity>(GetModel(specification));
orderBy(linq);
return linq.Queryable;
} public IQueryable<TEntity> GetModel(ISpecification<TEntity> specification)
{
return GetModel().Where(specification.SatisfiedBy());
} #endregion #region IOrderableRepository<TEntity>成员
public IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy)
{
var linq = new Orderable<TEntity>(GetModel());
orderBy(linq);
return linq.Queryable;
} public IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, Expression<Func<TEntity, bool>> predicate)
{
var linq = new Orderable<TEntity>(GetModel(predicate));
orderBy(linq);
return linq.Queryable;
}
#endregion #region Protected Methods
/// <summary>
/// 根据工作单元的IsNotSubmit的属性,去判断是否提交到数据库
/// 一般地,在多个repository类型进行组合时,这个IsNotSubmit都会设为true,即不马上提交,
/// 而对于单个repository操作来说,它的值不需要设置,使用默认的false,将直接提交到数据库,这也保证了操作的原子性。
/// </summary>
protected void SaveChanges()
{
try
{
Db.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)//捕获实体验证异常
{
var sb = new StringBuilder();
dbEx.EntityValidationErrors.First().ValidationErrors.ToList().ForEach(i =>
{
sb.AppendFormat("属性为:{0},信息为:{1}\n\r", i.PropertyName, i.ErrorMessage);
});
if (Logger == null)
throw new Exception(sb.ToString());
Logger(sb.ToString() + "处理时间:" + DateTime.Now); }
catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
{
//保持数据源中对象的现有属性
//Db.Refresh(RefreshMode.StoreWins, person);
// Db.SaveChanges();
}
catch (Exception ex)//捕获所有异常
{
if (Logger == null)//如果没有定义日志功能,就把异常抛出来吧
throw new Exception(ex.Message);
Logger(ex.Message + "处理时间:" + DateTime.Now);
} } /// <summary>
/// 计数更新,与SaveChange()是两个SQL链接,走分布式事务
/// 子类可以根据自己的逻辑,去复写
/// tableName:表名
/// param:索引0为主键名,1表主键值,2为要计数的字段,3为增量
/// </summary>
/// <param name="tableName">表名</param>
/// <param name="param">参数列表,索引0为主键名,1表主键值,2为要计数的字段,3为增量</param>
protected virtual void UpdateForCount(string tableName, params object[] param)
{
string sql = "update [" + tableName + "] set [{2}]=ISNULL([{2}],0)+{3} where [{0}]={1}";
var listParasm = new List<object>
{
param[],
param[],
param[],
param[],
};
Db.Database.ExecuteSqlCommand(string.Format(sql, listParasm.ToArray()));
}
#endregion #region Virtual Methods /// <summary>
/// Called after data saved
/// </summary>
/// <param name="e"></param>
protected virtual void OnAfterSaved(SavedEventArgs e)
{
if (AfterSaved != null)
{
AfterSaved(e);
}
} /// <summary>
/// Called before saved
/// </summary>
/// <param name="e"></param>
protected virtual void OnBeforeSaved(SavedEventArgs e)
{
if (BeforeSaved != null)
{
BeforeSaved(e);
}
} #endregion #region Private Methods /// <summary>
/// 分页进行数据提交的逻辑
/// </summary>
/// <param name="item">原列表</param>
/// <param name="method">处理方法</param>
/// <param name="currentItem">要进行处理的新列表</param>
private void DataPageProcess(IEnumerable<TEntity> item, Action<IEnumerable<TEntity>> method)
{
if (item != null && item.Any())
{
_dataTotalCount = item.Count();
this._dataTotalPages = item.Count() / DataPageSize;
if (_dataTotalCount % DataPageSize > )
_dataTotalPages += ;
for (int pageIndex = ; pageIndex <= _dataTotalPages; pageIndex++)
{
var currentItems = item.Skip((pageIndex - ) * DataPageSize).Take(DataPageSize).ToList();
method(currentItems);
}
}
} private static string GetEqualStatment(string fieldName, int paramId, Type pkType)
{
if (pkType.IsValueType)
return string.Format("{0} = {1}", fieldName, GetParamTag(paramId));
return string.Format("{0} = '{1}'", fieldName, GetParamTag(paramId)); } private static string GetParamTag(int paramId)
{
return "{" + paramId + "}";
} /// <summary>
/// 得到实体键EntityKey
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <returns></returns>
protected ReadOnlyMetadataCollection<EdmMember> GetPrimaryKey()
{
EntitySetBase primaryKey = ((IObjectContextAdapter)Db).ObjectContext.GetEntitySet(typeof(TEntity));
if (primaryKey == null)
return null;
ReadOnlyMetadataCollection<EdmMember> arr = primaryKey.ElementType.KeyMembers;
return arr;
} /// <summary>
/// 构建Update语句串
/// 注意:如果本方法过滤了int,decimal类型更新为0的列,如果希望更新它们需要指定FieldParams参数
/// </summary>
/// <param name="entity">实体列表</param>
/// <param name="fieldParams">要更新的字段</param>
/// <returns></returns>
private Tuple<string, object[]> CreateUpdateSql(TEntity entity, params string[] fieldParams)
{
if (entity == null)
throw new ArgumentException("The database entity can not be null.");
var pkList = GetPrimaryKey().Select(i => i.Name).ToList(); var entityType = entity.GetType();
var tableFields = new List<PropertyInfo>();
if (fieldParams != null && fieldParams.Count() > )
{
tableFields = entityType.GetProperties().Where(i => fieldParams.Contains(i.Name, new StringComparisonIgnoreCase())).ToList();
}
else
{
tableFields = entityType.GetProperties().Where(i =>
!pkList.Contains(i.Name)
&& i.GetValue(entity, null) != null
&& !i.PropertyType.IsEnum
&& !(i.PropertyType == typeof(ValueType) && Convert.ToInt64(i.GetValue(entity, null)) == )
&& !(i.PropertyType == typeof(DateTime) && Convert.ToDateTime(i.GetValue(entity, null)) == DateTime.MinValue)
&& i.PropertyType != typeof(EntityState)
&& i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null//过滤导航属性
&& (i.PropertyType.IsValueType || i.PropertyType == typeof(string))
).ToList();
} //过滤主键,航行属性,状态属性等
if (pkList == null || pkList.Count == )
throw new ArgumentException("The Table entity have not a primary key.");
var arguments = new List<object>();
var builder = new StringBuilder(); foreach (var change in tableFields)
{
if (pkList.Contains(change.Name))
continue;
if (arguments.Count != )
builder.Append(", ");
builder.Append(change.Name + " = {" + arguments.Count + "}");
if (change.PropertyType == typeof(string)
|| change.PropertyType == typeof(DateTime)
|| change.PropertyType == typeof(DateTime?)
|| change.PropertyType == typeof(bool?)
|| change.PropertyType == typeof(bool))
arguments.Add("'" + change.GetValue(entity, null).ToString().Replace("'", "char(39)") + "'");
else
arguments.Add(change.GetValue(entity, null));
} if (builder.Length == )
throw new Exception("没有任何属性进行更新"); builder.Insert(, " UPDATE " + string.Format("[{0}]", entityType.Name) + " SET "); builder.Append(" WHERE ");
bool firstPrimaryKey = true; foreach (var primaryField in pkList)
{
if (firstPrimaryKey)
firstPrimaryKey = false;
else
builder.Append(" AND "); object val = entityType.GetProperty(primaryField).GetValue(entity, null);
Type pkType = entityType.GetProperty(primaryField).GetType();
builder.Append(GetEqualStatment(primaryField, arguments.Count, pkType));
arguments.Add(val);
}
return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray()); } /// <summary>
/// 构建Delete语句串
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
private Tuple<string, object[]> CreateDeleteSql(TEntity entity)
{
if (entity == null)
throw new ArgumentException("The database entity can not be null."); Type entityType = entity.GetType();
List<string> pkList = GetPrimaryKey().Select(i => i.Name).ToList();
if (pkList == null || pkList.Count == )
throw new ArgumentException("The Table entity have not a primary key."); var arguments = new List<object>();
var builder = new StringBuilder();
builder.Append(" Delete from " + string.Format("[{0}]", entityType.Name)); builder.Append(" WHERE ");
bool firstPrimaryKey = true; foreach (var primaryField in pkList)
{
if (firstPrimaryKey)
firstPrimaryKey = false;
else
builder.Append(" AND "); Type pkType = entityType.GetProperty(primaryField).GetType();
object val = entityType.GetProperty(primaryField).GetValue(entity, null);
builder.Append(GetEqualStatment(primaryField, arguments.Count, pkType));
arguments.Add(val);
}
return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray());
} /// <summary>
/// 构建Insert语句串
/// 主键为自增时,如果主键值为0,我们将主键插入到SQL串中
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
private Tuple<string, object[]> CreateInsertSql(TEntity entity)
{
if (entity == null)
throw new ArgumentException("The database entity can not be null."); Type entityType = entity.GetType();
var table = entityType.GetProperties().Where(i => i.PropertyType != typeof(EntityKey)
&& i.PropertyType != typeof(EntityState)
&& i.Name != "IsValid"
&& i.GetValue(entity, null) != null
&& !i.PropertyType.IsEnum
&& i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null
&& (i.PropertyType.IsValueType || i.PropertyType == typeof(string))).ToArray();//过滤主键,航行属性,状态属性等 var pkList = new List<string>();
if (GetPrimaryKey() != null)//有时主键可能没有设计,这对于添加操作是可以的
pkList = GetPrimaryKey().Select(i => i.Name).ToList();
var arguments = new List<object>();
var fieldbuilder = new StringBuilder();
var valuebuilder = new StringBuilder(); fieldbuilder.Append(" INSERT INTO " + string.Format("[{0}]", entityType.Name) + " ("); foreach (var member in table)
{
if (pkList.Contains(member.Name) && Convert.ToString(member.GetValue(entity, null)) == "")
continue;
object value = member.GetValue(entity, null);
if (value != null)
{
if (arguments.Count != )
{
fieldbuilder.Append(", ");
valuebuilder.Append(", ");
} fieldbuilder.Append(member.Name);
if (member.PropertyType == typeof(string)
|| member.PropertyType == typeof(DateTime)
|| member.PropertyType == typeof(DateTime?)
|| member.PropertyType == typeof(Boolean?)
|| member.PropertyType == typeof(Boolean)
)
valuebuilder.Append("'{" + arguments.Count + "}'");
else
valuebuilder.Append("{" + arguments.Count + "}");
if (value is string)
value = value.ToString().Replace("'", "char(39)");
arguments.Add(value); }
} fieldbuilder.Append(") Values ("); fieldbuilder.Append(valuebuilder.ToString());
fieldbuilder.Append(");");
return new Tuple<string, object[]>(fieldbuilder.ToString(), arguments.ToArray());
} /// <summary>
/// /// <summary>
/// 执行SQL,根据SQL操作的类型
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="list"></param>
/// <param name="sqlType"></param>
/// <returns></returns>
/// </summary>
/// <param name="list"></param>
/// <param name="sqlType"></param>
/// <returns></returns>
private string DoSql(IEnumerable<TEntity> list, SqlType sqlType)
{
return DoSql(list, sqlType, null);
}
/// <summary>
/// 执行SQL,根据SQL操作的类型
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="list"></param>
/// <param name="sqlType"></param>
/// <returns></returns>
private string DoSql(IEnumerable<TEntity> list, SqlType sqlType, params string[] fieldParams)
{
var sqlstr = new StringBuilder();
switch (sqlType)
{
case SqlType.Insert:
list.ToList().ForEach(i =>
{
Tuple<string, object[]> sql = CreateInsertSql(i);
sqlstr.AppendFormat(sql.Item1, sql.Item2);
});
break;
case SqlType.Update:
list.ToList().ForEach(i =>
{
Tuple<string, object[]> sql = CreateUpdateSql(i, fieldParams);
sqlstr.AppendFormat(sql.Item1, sql.Item2);
});
break;
case SqlType.Delete:
list.ToList().ForEach(i =>
{
Tuple<string, object[]> sql = CreateDeleteSql(i);
sqlstr.AppendFormat(sql.Item1, sql.Item2);
});
break;
default:
throw new ArgumentException("请输入正确的参数");
}
return sqlstr.ToString();
} /// <summary>
/// SQL操作类型
/// </summary>
protected enum SqlType
{
Insert,
Update,
Delete,
}
#endregion }
以上六大部分就是我最新的EF架构的核心了,事实上,EF只是实现数据持久化的一种方式,在我的架构中还提到了XmlRepository,RedisRepository,Linq2SqlRepository等等,对于仓储这块感兴趣的同学,可以与我一起去讨论!我很希望有一天,我的底层
架构有这样一个功能,那就是自动去选择我的数据库,如我的数据库有db1,db2.....dbN,它们之间的数据是同步的(集群),我能通过EF来实现我用哪台数据服务器,想想就很美,哈哈!
EF架构~基于EF数据层的实现的更多相关文章
- EF架构~为EF DbContext生成的实体添加注释(T5模板应用)
回到目录 相关文章系列 第八回 EF架构~将数据库注释添加导入到模型实体类中 第二十一回 EF架构~为EF DbContext生成的实体添加注释(T4模板应用) 第二十二回EF架构~为EF DbCo ...
- EF架构~为EF DbContext生成的实体添加注释(T5模板应用)(转载)
转载地址:http://www.newlifex.com/showtopic-1072.aspx 最近新项目要用Entity Framework 6.x,但是我发现从数据库生成模型时没有生成字段的注释 ...
- 【转】EF架构~为EF DbContext生成的实体添加注释(T5模板应用)
嗨,没法说,EF4的TT模版加上注释后,升级到EF5的TT模版后,注释就不通用了,所以,还得再研究一下,然后把操作方法再分享出来,没辙的微软! T4模版可能有些凌乱,这在T5模版里有了不错的改进,但我 ...
- EF架构~在ef中支持IQueryable级别的Contains被翻译成了Exists,性能可以接受!
回到目录 Entityframeworks很聪明 不错,非常不错!ef里的contains比linq to sql里的contains有了明显的提升,事实上,是在进行SQL语句翻译上有所提升,在lin ...
- 分享基于EF+MVC+Bootstrap的通用后台管理系统及架构
基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业 ...
- 分享我们项目中基于EF事务机制的架构
写在前面: 1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库. 2. 本文中的单元测试都是正确通过的. 要理解EF的事务机制,首先要理解这2个类:TransactionSco ...
- 分享基于EF+MVC+Bootstrap的通用后台管理系统及架构(转)
http://www.cnblogs.com/guozili/p/3496265.html 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通 ...
- 基于EF+WCF的通用三层架构及解析
分享基于EF+WCF的通用三层架构及解析 本项目结合EF 4.3及WCF实现了经典三层架构,各层面向接口,WCF实现SOA,Repository封装调用,在此基础上实现了WCFContext,动态服务 ...
- 基于EF+MVC+Bootstrap的通用后台管理系统及架构
分享基于EF+MVC+Bootstrap的通用后台管理系统及架构 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了 ...
随机推荐
- 【Java源码分析】LinkedList类
LinkedList<E> 源码解读 继承AbstractSequentialList<E> 实现List<E>, Deque<E>, Cloneabl ...
- sharebutton
<h1>Share Buttons</h1> <!-- Twitter --> <a href="http://twitter.com/share? ...
- linux环境下安装mongodb
最近有用到mongodb,顺便找到了以前的指南,顺便写一篇随笔,以后或许有用到的地方. 第一步:下载mongodb的linux版本,mongodb-linux-x86_64-3.2.4.tgz(去官网 ...
- 使用html2canvas实现网页截图并嵌入到PDF
以前我们只能通过截图工具进行截取图像.这使得在业务生产中,变得越来越不方便.目前的浏览器功能越来越强大,H5也逐渐普及,浏览器也可以实现截图了.这里来聊下之前在工作中用到的html2canvas.这里 ...
- react通过自己的jsx语法将两者放在一起通过虚拟dom来渲染
目前较为流行的react确实有很多优点,例如虚拟dom,单向数据流状态机的思想.还有可复用组件化的思想等等.加上搭配jsx语法和es6,适应之后开发确实快捷很多,值得大家去一试.其实组件化的思想一直在 ...
- 『TCP/IP详解——卷一:协议』读书笔记——15
2013-08-25 13:39:40 第6章 ICMP:Internet控制报文协议 6.1 引言 ICMP经常被认为是IP层的一个组成部分.它传递差错报文以及其他需要注意的信息.ICMP报文同通常 ...
- berkeley db中 dirty read的实现
dirty reader怎样 不被writor block住? 如数据库支持dirty read, 则 所有打开的dbhandle都配置 DB_READ_UNCOMMITTED; 在线程拿到 writ ...
- 前端学习之touch.js与swiper学习
Touch.js是移动设备上的手势识别与事件库,改框架基于原生js,操作简单,主要分drag,swipe,rotate,scale,tab,hold,touch操作. swiper是一个移动端触摸滑动 ...
- oracle 读书笔记
1 动态sql即拼接字符串的sql,使用变量代替具体值,10万条语句可以被hash陈一个SQL_ID,可以只解析一次 for i in 1..100000 loop execute immediate ...
- Byte,TBytes,array of Byte, array[0..9] of byte的区别
Byte前面已经说是存放bit的单元,是电脑内存的基本单位,byte表示0-255中的256个数字 下面为Byte的用法: var B: Byte; // 表示0-255的数字 begin B := ...