勤奋是你生命的密码,能译出你一部壮丽的史诗。
Dapper简单的CRUD帮助类
public static partial class SimpleCRUD
{
public enum Dialect
{
SQLServer,
PostgreSQL,
SQLite,
MySQL,
}
private static Dialect _dialect = Dialect.SQLServer;
private static string _encapsulation;
private static string _getIdentitySql;
private static string _getPagedListSql;
static SimpleCRUD()
{
SetDialect(_dialect);
}
public static string GetDialect()
{
return _dialect.ToString();
}
public static void SetDialect(Dialect dialect)
{
switch (dialect)
{
case Dialect.PostgreSQL:
_dialect = Dialect.PostgreSQL;
_encapsulation = "{0}";
_getIdentitySql = string.Format("SELECT LASTVAL() AS id");
_getPagedListSql =
"Select {SelectColumns} from {TableName} {WhereClause} Order By {OrderBy} LIMIT {RowsPerPage} OFFSET (({PageNumber}-1) * {RowsPerPage})";
break;
case Dialect.SQLite:
_dialect = Dialect.SQLite;
_encapsulation = "{0}";
_getIdentitySql = string.Format("SELECT LAST_INSERT_ROWID() AS id");
_getPagedListSql =
"Select {SelectColumns} from {TableName} {WhereClause} Order By {OrderBy} LIMIT {RowsPerPage} OFFSET (({PageNumber}-1) * {RowsPerPage})";
break;
case Dialect.MySQL:
_dialect = Dialect.MySQL;
_encapsulation = "`{0}`";
_getIdentitySql = string.Format("SELECT LAST_INSERT_ID() AS id");
_getPagedListSql =
"Select {SelectColumns} from {TableName} {WhereClause} Order By {OrderBy} LIMIT {Offset},{RowsPerPage}";
break;
default:
_dialect = Dialect.SQLServer;
_encapsulation = "[{0}]";
_getIdentitySql = string.Format("SELECT CAST(SCOPE_IDENTITY() AS BIGINT) AS [id]");
_getPagedListSql =
"SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY {OrderBy}) AS PagedNumber, {SelectColumns} FROM {TableName} {WhereClause}) AS u WHERE PagedNUMBER BETWEEN (({PageNumber}-1) * {RowsPerPage} + 1) AND ({PageNumber} * {RowsPerPage})";
break;
}
}
public static T Get<T>(this IDbConnection connection, object id, IDbTransaction transaction = null,
int? commandTimeout = null)
{
Type currenttype = typeof (T);
List<PropertyInfo> idProps = GetIdProperties(currenttype).ToList();
if (!idProps.Any())
throw new ArgumentException("Get<T> only supports an entity with a [Key] or Id property");
if (idProps.Count() > 1)
throw new ArgumentException("Get<T> only supports an entity with a single [Key] or Id property");
PropertyInfo onlyKey = idProps.First();
string name = GetTableName(currenttype);
var sb = new StringBuilder();
sb.Append("Select ");
BuildSelect(sb, GetScaffoldableProperties((T) Activator.CreateInstance(typeof (T))).ToArray());
sb.AppendFormat(" from {0}", name);
sb.Append(" where " + GetColumnName(onlyKey) + " = @Id");
var dynParms = new DynamicParameters();
dynParms.Add("@id", id);
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("Get<{0}>: {1} with Id: {2}", currenttype, sb, id));
return connection.Query<T>(sb.ToString(), dynParms, transaction, true, commandTimeout).FirstOrDefault();
}
public static IEnumerable<T> GetList<T>(this IDbConnection connection, object whereConditions,
IDbTransaction transaction = null, int? commandTimeout = null)
{
Type currenttype = typeof (T);
List<PropertyInfo> idProps = GetIdProperties(currenttype).ToList();
if (!idProps.Any())
throw new ArgumentException("Entity must have at least one [Key] property");
string name = GetTableName(currenttype);
var sb = new StringBuilder();
PropertyInfo[] whereprops = GetAllProperties(whereConditions).ToArray();
sb.Append("Select ");
BuildSelect(sb, GetScaffoldableProperties((T) Activator.CreateInstance(typeof (T))).ToArray());
sb.AppendFormat(" from {0}", name);
if (whereprops.Any())
{
sb.Append(" where ");
BuildWhere(sb, whereprops, (T) Activator.CreateInstance(typeof (T)), whereConditions);
}
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("GetList<{0}>: {1}", currenttype, sb));
return connection.Query<T>(sb.ToString(), whereConditions, transaction, true, commandTimeout);
}
public static IEnumerable<T> GetList<T>(this IDbConnection connection, string conditions,
IDbTransaction transaction = null, int? commandTimeout = null)
{
Type currenttype = typeof (T);
List<PropertyInfo> idProps = GetIdProperties(currenttype).ToList();
if (!idProps.Any())
throw new ArgumentException("Entity must have at least one [Key] property");
string name = GetTableName(currenttype);
var sb = new StringBuilder();
sb.Append("Select ");
BuildSelect(sb, GetScaffoldableProperties((T) Activator.CreateInstance(typeof (T))).ToArray());
sb.AppendFormat(" from {0}", name);
sb.Append(" " + conditions);
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("GetList<{0}>: {1}", currenttype, sb));
return connection.Query<T>(sb.ToString(), null, transaction, true, commandTimeout);
}
public static IEnumerable<T> GetList<T>(this IDbConnection connection)
{
return connection.GetList<T>(new {});
}
public static IEnumerable<T> GetListPaged<T>(this IDbConnection connection, int pageNumber, int rowsPerPage,
string conditions, string orderby, IDbTransaction transaction = null, int? commandTimeout = null)
{
if (string.IsNullOrEmpty(_getPagedListSql))
throw new Exception("GetListPage is not supported with the current SQL Dialect");
if (pageNumber < 1)
throw new Exception("Page must be greater than 0");
Type currenttype = typeof (T);
List<PropertyInfo> idProps = GetIdProperties(currenttype).ToList();
if (!idProps.Any())
throw new ArgumentException("Entity must have at least one [Key] property");
string name = GetTableName(currenttype);
var sb = new StringBuilder();
string query = _getPagedListSql;
if (string.IsNullOrEmpty(orderby))
{
orderby = GetColumnName(idProps.First());
}
BuildSelect(sb, GetScaffoldableProperties((T) Activator.CreateInstance(typeof (T))).ToArray());
query = query.Replace("{SelectColumns}", sb.ToString());
query = query.Replace("{TableName}", name);
query = query.Replace("{PageNumber}", pageNumber.ToString());
query = query.Replace("{RowsPerPage}", rowsPerPage.ToString());
query = query.Replace("{OrderBy}", orderby);
query = query.Replace("{WhereClause}", conditions);
query = query.Replace("{Offset}", ((pageNumber - 1)*rowsPerPage).ToString());
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("GetListPaged<{0}>: {1}", currenttype, query));
return connection.Query<T>(query, null, transaction, true, commandTimeout);
}
public static int? Insert(this IDbConnection connection, object entityToInsert,
IDbTransaction transaction = null, int? commandTimeout = null)
{
return Insert<int?>(connection, entityToInsert, transaction, commandTimeout);
}
public static TKey Insert<TKey>(this IDbConnection connection, object entityToInsert,
IDbTransaction transaction = null, int? commandTimeout = null)
{
List<PropertyInfo> idProps = GetIdProperties(entityToInsert).ToList();
if (!idProps.Any())
throw new ArgumentException("Insert<T> only supports an entity with a [Key] or Id property");
if (idProps.Count() > 1)
throw new ArgumentException("Insert<T> only supports an entity with a single [Key] or Id property");
bool keyHasPredefinedValue = false;
Type baseType = typeof (TKey);
Type underlyingType = Nullable.GetUnderlyingType(baseType);
Type keytype = underlyingType ?? baseType;
if (keytype != typeof (int) && keytype != typeof (uint) && keytype != typeof (long) &&
keytype != typeof (ulong) && keytype != typeof (short) && keytype != typeof (ushort) &&
keytype != typeof (Guid))
{
throw new Exception("Invalid return type");
}
string name = GetTableName(entityToInsert);
var sb = new StringBuilder();
sb.AppendFormat("insert into {0}", name);
sb.Append(" (");
BuildInsertParameters(entityToInsert, sb);
sb.Append(") ");
sb.Append("values");
sb.Append(" (");
BuildInsertValues(entityToInsert, sb);
sb.Append(")");
if (keytype == typeof (Guid))
{
var guidvalue = (Guid) idProps.First().GetValue(entityToInsert, null);
if (guidvalue == Guid.Empty)
{
Guid newguid = SequentialGuid();
idProps.First().SetValue(entityToInsert, newguid, null);
}
else
{
keyHasPredefinedValue = true;
}
sb.Append(";select '" + idProps.First().GetValue(entityToInsert, null) + "' as id");
}
if ((keytype == typeof (int) || keytype == typeof (long)) &&
Convert.ToInt64(idProps.First().GetValue(entityToInsert, null)) == 0)
{
sb.Append(";" + _getIdentitySql);
}
else
{
keyHasPredefinedValue = true;
}
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("Insert: {0}", sb));
IEnumerable<dynamic> r = connection.Query(sb.ToString(), entityToInsert, transaction, true, commandTimeout);
if (keytype == typeof (Guid) || keyHasPredefinedValue)
{
return (TKey) idProps.First().GetValue(entityToInsert, null);
}
return (TKey) r.First().id;
}
public static int Update(this IDbConnection connection, object entityToUpdate, IDbTransaction transaction = null,
int? commandTimeout = null)
{
List<PropertyInfo> idProps = GetIdProperties(entityToUpdate).ToList();
if (!idProps.Any())
throw new ArgumentException("Entity must have at least one [Key] or Id property");
string name = GetTableName(entityToUpdate);
var sb = new StringBuilder();
sb.AppendFormat("update {0}", name);
sb.AppendFormat(" set ");
BuildUpdateSet(entityToUpdate, sb);
sb.Append(" where ");
BuildWhere(sb, idProps, entityToUpdate);
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("Update: {0}", sb));
return connection.Execute(sb.ToString(), entityToUpdate, transaction, commandTimeout);
}
public static int Delete<T>(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null,
int? commandTimeout = null)
{
List<PropertyInfo> idProps = GetIdProperties(entityToDelete).ToList();
if (!idProps.Any())
throw new ArgumentException("Entity must have at least one [Key] or Id property");
string name = GetTableName(entityToDelete);
var sb = new StringBuilder();
sb.AppendFormat("delete from {0}", name);
sb.Append(" where ");
BuildWhere(sb, idProps, entityToDelete);
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("Delete: {0}", sb));
return connection.Execute(sb.ToString(), entityToDelete, transaction, commandTimeout);
}
public static int Delete<T>(this IDbConnection connection, object id, IDbTransaction transaction = null,
int? commandTimeout = null)
{
Type currenttype = typeof (T);
List<PropertyInfo> idProps = GetIdProperties(currenttype).ToList();
if (!idProps.Any())
throw new ArgumentException("Delete<T> only supports an entity with a [Key] or Id property");
if (idProps.Count() > 1)
throw new ArgumentException("Delete<T> only supports an entity with a single [Key] or Id property");
PropertyInfo onlyKey = idProps.First();
string name = GetTableName(currenttype);
var sb = new StringBuilder();
sb.AppendFormat("Delete from {0}", name);
sb.Append(" where " + GetColumnName(onlyKey) + " = @Id");
var dynParms = new DynamicParameters();
dynParms.Add("@id", id);
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("Delete<{0}> {1}", currenttype, sb));
return connection.Execute(sb.ToString(), dynParms, transaction, commandTimeout);
}
public static int DeleteList<T>(this IDbConnection connection, object whereConditions,
IDbTransaction transaction = null, int? commandTimeout = null)
{
Type currenttype = typeof (T);
string name = GetTableName(currenttype);
var sb = new StringBuilder();
PropertyInfo[] whereprops = GetAllProperties(whereConditions).ToArray();
sb.AppendFormat("Delete from {0}", name);
if (whereprops.Any())
{
sb.Append(" where ");
BuildWhere(sb, whereprops, (T) Activator.CreateInstance(typeof (T)));
}
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("DeleteList<{0}> {1}", currenttype, sb));
return connection.Execute(sb.ToString(), whereConditions, transaction, commandTimeout);
}
public static int DeleteList<T>(this IDbConnection connection, string conditions,
IDbTransaction transaction = null, int? commandTimeout = null)
{
if (string.IsNullOrEmpty(conditions))
throw new ArgumentException("DeleteList<T> requires a where clause");
if (!conditions.ToLower().Contains("where"))
throw new ArgumentException("DeleteList<T> requires a where clause and must contain the WHERE keyword");
Type currenttype = typeof (T);
string name = GetTableName(currenttype);
var sb = new StringBuilder();
sb.AppendFormat("Delete from {0}", name);
sb.Append(" " + conditions);
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("DeleteList<{0}> {1}", currenttype, sb));
return connection.Execute(sb.ToString(), null, transaction, commandTimeout);
}
public static int RecordCount<T>(this IDbConnection connection, string conditions = "",
IDbTransaction transaction = null, int? commandTimeout = null)
{
Type currenttype = typeof (T);
string name = GetTableName(currenttype);
var sb = new StringBuilder();
sb.Append("Select count(1)");
sb.AppendFormat(" from {0}", name);
sb.Append(" " + conditions);
if (Debugger.IsAttached)
Trace.WriteLine(String.Format("RecordCount<{0}>: {1}", currenttype, sb));
return connection.Query<int>(sb.ToString(), null, transaction, true, commandTimeout).Single();
}
private static void BuildUpdateSet(object entityToUpdate, StringBuilder sb)
{
PropertyInfo[] nonIdProps = GetUpdateableProperties(entityToUpdate).ToArray();
for (int i = 0; i < nonIdProps.Length; i++)
{
PropertyInfo property = nonIdProps[i];
sb.AppendFormat("{0} = @{1}", GetColumnName(property), property.Name);
if (i < nonIdProps.Length - 1)
sb.AppendFormat(", ");
}
}
private static void BuildSelect(StringBuilder sb, IEnumerable<PropertyInfo> props)
{
IList<PropertyInfo> propertyInfos = props as IList<PropertyInfo> ?? props.ToList();
bool addedAny = false;
for (int i = 0; i < propertyInfos.Count(); i++)
{
if (
propertyInfos.ElementAt(i)
.GetCustomAttributes(true)
.Any(attr => attr.GetType().Name == "IgnoreSelectAttribute")) continue;
if (addedAny)
sb.Append(",");
sb.Append(GetColumnName(propertyInfos.ElementAt(i)));
if (
propertyInfos.ElementAt(i)
.GetCustomAttributes(true)
.SingleOrDefault(attr => attr.GetType().Name == "ColumnAttribute") != null)
sb.Append(" as " + propertyInfos.ElementAt(i).Name);
addedAny = true;
}
}
private static void BuildWhere(StringBuilder sb, IEnumerable<PropertyInfo> idProps, object sourceEntity,
object whereConditions = null)
{
PropertyInfo[] propertyInfos = idProps.ToArray();
for (int i = 0; i < propertyInfos.Count(); i++)
{
bool useIsNull = false;
PropertyInfo propertyToUse = propertyInfos.ElementAt(i);
PropertyInfo[] sourceProperties = GetScaffoldableProperties(sourceEntity).ToArray();
for (int x = 0; x < sourceProperties.Count(); x++)
{
if (sourceProperties.ElementAt(x).Name == propertyInfos.ElementAt(i).Name)
{
propertyToUse = sourceProperties.ElementAt(x);
if (whereConditions != null && propertyInfos.ElementAt(i).CanRead &&
(propertyInfos.ElementAt(i).GetValue(whereConditions, null) == null ||
propertyInfos.ElementAt(i).GetValue(whereConditions, null) == DBNull.Value))
{
useIsNull = true;
}
break;
}
}
sb.AppendFormat(
useIsNull ? "{0} is null" : "{0} = @{1}",
GetColumnName(propertyToUse),
propertyInfos.ElementAt(i).Name);
if (i < propertyInfos.Count() - 1)
sb.AppendFormat(" and ");
}
}
private static void BuildInsertValues(object entityToInsert, StringBuilder sb)
{
PropertyInfo[] props = GetScaffoldableProperties(entityToInsert).ToArray();
for (int i = 0; i < props.Count(); i++)
{
PropertyInfo property = props.ElementAt(i);
if (property.PropertyType != typeof (Guid)
&& property.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "KeyAttribute")
&& property.GetCustomAttributes(true).All(attr => attr.GetType().Name != "RequiredAttribute"))
continue;
if (property.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "IgnoreInsertAttribute"))
continue;
if (
property.GetCustomAttributes(true)
.Any(attr => attr.GetType().Name == "ReadOnlyAttribute" && IsReadOnly(property))) continue;
if (property.Name == "Id" &&
property.GetCustomAttributes(true).All(attr => attr.GetType().Name != "RequiredAttribute") &&
property.PropertyType != typeof (Guid)) continue;
sb.AppendFormat("@{0}", property.Name);
if (i < props.Count() - 1)
sb.Append(", ");
}
if (sb.ToString().EndsWith(", "))
sb.Remove(sb.Length - 2, 2);
}
private static void BuildInsertParameters(object entityToInsert, StringBuilder sb)
{
PropertyInfo[] props = GetScaffoldableProperties(entityToInsert).ToArray();
for (int i = 0; i < props.Count(); i++)
{
PropertyInfo property = props.ElementAt(i);
if (property.PropertyType != typeof (Guid)
&& property.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "KeyAttribute")
&& property.GetCustomAttributes(true).All(attr => attr.GetType().Name != "RequiredAttribute"))
continue;
if (property.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "IgnoreInsertAttribute"))
continue;
if (
property.GetCustomAttributes(true)
.Any(attr => attr.GetType().Name == "ReadOnlyAttribute" && IsReadOnly(property))) continue;
if (property.Name == "Id" &&
property.GetCustomAttributes(true).All(attr => attr.GetType().Name != "RequiredAttribute") &&
property.PropertyType != typeof (Guid)) continue;
sb.Append(GetColumnName(property));
if (i < props.Count() - 1)
sb.Append(", ");
}
if (sb.ToString().EndsWith(", "))
sb.Remove(sb.Length - 2, 2);
}
private static IEnumerable<PropertyInfo> GetAllProperties(object entity)
{
if (entity == null) entity = new {};
return entity.GetType().GetProperties();
}
private static IEnumerable<PropertyInfo> GetScaffoldableProperties(object entity)
{
IEnumerable<PropertyInfo> props =
entity.GetType()
.GetProperties()
.Where(
p =>
p.GetCustomAttributes(true)
.Any(attr => attr.GetType().Name == "EditableAttribute" && !IsEditable(p)) == false);
return props.Where(p => p.PropertyType.IsSimpleType() || IsEditable(p));
}
private static bool IsEditable(PropertyInfo pi)
{
object[] attributes = pi.GetCustomAttributes(false);
if (attributes.Length > 0)
{
dynamic write = attributes.FirstOrDefault(x => x.GetType().Name == "EditableAttribute");
if (write != null)
{
return write.AllowEdit;
}
}
return false;
}
private static bool IsReadOnly(PropertyInfo pi)
{
object[] attributes = pi.GetCustomAttributes(false);
if (attributes.Length > 0)
{
dynamic write = attributes.FirstOrDefault(x => x.GetType().Name == "ReadOnlyAttribute");
if (write != null)
{
return write.IsReadOnly;
}
}
return false;
}
private static IEnumerable<PropertyInfo> GetUpdateableProperties(object entity)
{
IEnumerable<PropertyInfo> updateableProperties = GetScaffoldableProperties(entity);
updateableProperties = updateableProperties.Where(p => p.Name != "Id");
updateableProperties =
updateableProperties.Where(
p => p.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "KeyAttribute") == false);
updateableProperties =
updateableProperties.Where(
p =>
p.GetCustomAttributes(true)
.Any(attr => (attr.GetType().Name == "ReadOnlyAttribute") && IsReadOnly(p)) == false);
updateableProperties =
updateableProperties.Where(
p =>
p.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "IgnoreUpdateAttribute") == false);
return updateableProperties;
}
private static IEnumerable<PropertyInfo> GetIdProperties(object entity)
{
Type type = entity.GetType();
return GetIdProperties(type);
}
private static IEnumerable<PropertyInfo> GetIdProperties(Type type)
{
List<PropertyInfo> tp =
type.GetProperties()
.Where(p => p.GetCustomAttributes(true).Any(attr => attr.GetType().Name == "KeyAttribute"))
.ToList();
return tp.Any() ? tp : type.GetProperties().Where(p => p.Name == "Id");
}
private static string GetTableName(object entity)
{
Type type = entity.GetType();
return GetTableName(type);
}
private static string GetTableName(Type type)
{
string tableName = Encapsulate(type.Name);
var tableattr =
type.GetCustomAttributes(true).SingleOrDefault(attr => attr.GetType().Name == "TableAttribute") as
dynamic;
if (tableattr != null)
{
tableName = Encapsulate(tableattr.Name);
try
{
if (!String.IsNullOrEmpty(tableattr.Schema))
{
string schemaName = Encapsulate(tableattr.Schema);
tableName = String.Format("{0}.{1}", schemaName, tableName);
}
}
catch (RuntimeBinderException)
{
}
}
return tableName;
}
private static string GetColumnName(PropertyInfo propertyInfo)
{
string columnName = Encapsulate(propertyInfo.Name);
var columnattr =
propertyInfo.GetCustomAttributes(true).SingleOrDefault(attr => attr.GetType().Name == "ColumnAttribute")
as dynamic;
if (columnattr != null)
{
columnName = Encapsulate(columnattr.Name);
Trace.WriteLine(String.Format("Column name for type overridden from {0} to {1}", propertyInfo.Name,
columnName));
}
return columnName;
}
private static string Encapsulate(string databaseword)
{
return string.Format(_encapsulation, databaseword);
}
public static Guid SequentialGuid()
{
Guid tempGuid = Guid.NewGuid();
byte[] bytes = tempGuid.ToByteArray();
DateTime time = DateTime.Now;
bytes[3] = (byte) time.Year;
bytes[2] = (byte) time.Month;
bytes[1] = (byte) time.Day;
bytes[0] = (byte) time.Hour;
bytes[5] = (byte) time.Minute;
bytes[4] = (byte) time.Second;
return new Guid(bytes);
}
}
属性类:
[AttributeUsage(AttributeTargets.Class)]
public class TableAttribute : Attribute
{
public TableAttribute(string tableName)
{
Name = tableName;
}
public string Name { get; private set; }
public string Schema { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
public class ColumnAttribute : Attribute
{
public ColumnAttribute(string columnName)
{
Name = columnName;
}
public string Name { get; private set; }
}
[AttributeUsage(AttributeTargets.Property)]
public class KeyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class EditableAttribute : Attribute
{
public EditableAttribute(bool iseditable)
{
AllowEdit = iseditable;
}
public bool AllowEdit { get; private set; }
}
[AttributeUsage(AttributeTargets.Property)]
public class ReadOnlyAttribute : Attribute
{
public ReadOnlyAttribute(bool isReadOnly)
{
IsReadOnly = isReadOnly;
}
public bool IsReadOnly { get; private set; }
}
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreSelectAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreInsertAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreUpdateAttribute : Attribute
{
}
类型异常:
internal static class TypeExtension
{
public static bool IsSimpleType(this Type type)
{
Type underlyingType = Nullable.GetUnderlyingType(type);
type = underlyingType ?? type;
var simpleTypes = new List<Type>
{
typeof (byte),
typeof (sbyte),
typeof (short),
typeof (ushort),
typeof (int),
typeof (uint),
typeof (long),
typeof (ulong),
typeof (float),
typeof (double),
typeof (decimal),
typeof (bool),
typeof (string),
typeof (char),
typeof (Guid),
typeof (DateTime),
typeof (DateTimeOffset),
typeof (byte[])
};
return simpleTypes.Contains(type) || type.IsEnum;
}
}