【发布时间】:2018-06-29 20:31:49
【问题描述】:
我正在通过 EF Core 2.0 中的原始 SQL 命令编写 MySQL INSERT ... ON DUPLICATE KEY UPDATE 实现。我非常接近一个可行的解决方案,但我唯一的问题是确定通过反射读取的哪些 PropertyInfos 是主键。在下面的CreateUpdates() 方法中,如何从columnProperties 中过滤掉主键,使其不属于更新SQL 语句的一部分?
我尝试过使用 EntityFramework.PrimaryKey
,但我似乎无法让它与泛型 (TEntity) 一起使用。
我已经包含了我所有的相关代码,但我在这个问题中关注的部分是最后一个方法中的TODO,CreateUpdates()。
private static void InsertOnDuplicateKeyUpdate<TEntity>(DbContext dbContext) where TEntity : class
{
var columnProperties = GetColumnPropertiesLessBaseEntityTimestamps<TEntity>();
var tableName = GetTableName<TEntity>();
var columns = string.Join(", ", columnProperties.Select(x => x.Name));
var values = CreateValues<TEntity>(columnProperties);
var updates = CreateUpdates(columnProperties);
var rawSqlString = "INSERT INTO " + tableName + " (" + columns + ") VALUES " + values +
" ON DUPLICATE KEY UPDATE " + updates;
dbContext.Set<TEntity>().FromSql(rawSqlString);
dbContext.SaveChanges();
}
private static string GetTableName<TEntity>()
{
return typeof(TEntity).Name.Pluralize().ToLower();
}
private static List<PropertyInfo> GetColumnPropertiesLessBaseEntityTimestamps<TEntity>()
{
return typeof(TEntity).GetProperties().Where(x =>
x.PropertyType.Namespace != "System.Collections.Generic" &&
!new List<string> {"CreatedDateUtc", "ModifiedDateUtc"}.Contains(x.Name)).ToList();
}
private static string CreateValues<TEntity>(IReadOnlyCollection<PropertyInfo> columnProperties)
{
return GetSeedRows<TEntity>().Select(row => CreateRowValues(columnProperties, row)).Aggregate("",
(current, rowValues) => current == "" ? rowValues : current + ", " + rowValues);
}
private static string CreateRowValues<TEntity>(IEnumerable<PropertyInfo> columnProperties, TEntity row)
{
return (from property in columnProperties
let value = row.GetType().GetProperty(property.Name).GetValue(row)
select WrapStringPropertyValueInSingleQuotes(property, value)).Aggregate("",
(current, value) => current == "" ? "(" + value : current + ", " + value) + ")";
}
private static object WrapStringPropertyValueInSingleQuotes(PropertyInfo property, object value)
{
if (property.PropertyType == typeof(string))
value = "'" + value + "'";
return value;
}
private static string CreateUpdates(IEnumerable<PropertyInfo> columnProperties)
{
//TODO: filter out primary keys from columnProperties
return columnProperties.Select(property => property.Name).Aggregate("", (current, column) => current == ""
? column + " = VALUES(" + column + ")"
: current + ", " + column + " = VALUES(" + column + ")");
}
【问题讨论】:
标签: mysql generics reflection asp.net-core entity-framework-core