【问题标题】:Determine which PropertyInfos of a generic TEntity are primary keys via reflection通过反射确定通用 TEntity 的哪些 PropertyInfos 是主键
【发布时间】:2018-06-29 20:31:49
【问题描述】:

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

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

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

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 哇,谢谢!我不知道我的 Google-Fu 是如何没有引导我使用 dbContext.Model.FindEntityType() API 的。这很漂亮。
    猜你喜欢
    • 1970-01-01
    • 2013-02-18
    • 2010-11-07
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多