mysql - 通过反射确定泛型 TEntity 的哪些 PropertyInfo 是主键

标签 mysql generics reflection asp.net-core entity-framework-core

我正在通过 EF Core 2.0 中的原始 SQL 命令编写 MySQL INSERT ... ON DUPLICATE KEY UPDATE 实现。我非常接近一个可行的解决方案,但我遇到的唯一问题是确定通过反射读取的哪些 PropertyInfo 是主键。在下面的 CreateUpdates() 方法中,如何从 columnProperties 中过滤出主键,使它们不属于更新 SQL 语句的一部分?

我试过使用 EntityFramework.PrimaryKey ,但我似乎无法让它与泛型一起工作 (TEntity)。

我已经包含了所有相关代码,但我在这个问题中关注的部分是最后一个方法 CreateUpdates() 中的TODO

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 + ")");
}

最佳答案

在 ef-core 中,从映射模型中检索元数据变得更加容易。您可以通过以下行获取主键的 PropertyInfo:

var keyPropertyInfos = dbContext.Model.FindEntityType(typeof(TEntity))
    .FindPrimaryKey()
    .Properties
    .Select(p => p.PropertyInfo);

顺便说一句,您可以通过将 FindPrimaryKey().Properties 替换为 GetProperties() 来获取所有(映射的)属性;

关于mysql - 通过反射确定泛型 TEntity 的哪些 PropertyInfo 是主键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48360765/

相关文章:

c# - 无法在泛型方法中将类型更改为可为空

generics - 我如何通用化 Yew Web 请求

mysql - 如何使用单个查询更新两行的交换值

c# - dbSet Add - "No Duplicate Primary Key:"字段不自动递增

java - 使用 Guava 从列表中删除重复项

java 。如何通过反射获取不可为空的字段?

java - java反射类

java - 在 JUnit 的测试类中定义内部类时出错

mysql - 查找所有不在数据库中的值

mysql - 如何合并所有并按多个选择分组而不输出空?