filter primary keys from updates, other cleanup

per: https://stackoverflow.com/a/48361472/2343739
This commit is contained in:
Collin M. Barrett 2018-01-20 18:58:43 -06:00
parent e28336515a
commit fe04bd8cd5
2 changed files with 44 additions and 53 deletions

View file

@ -6,7 +6,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.2.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.1.1" />
<PackageReference Include="Microsoft.DotNet.Analyzers.Compatibility" Version="0.1.2-alpha" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.1" />

View file

@ -1,11 +1,11 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using FilterLists.Data.Entities;
using Humanizer;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Newtonsoft.Json;
@ -28,29 +28,29 @@ public static void EnsureSeeded(this FilterListsDbContext context)
SeedEntities(context);
//InsertOnDuplicateKeyUpdateEntities(context);
SeedJunctions(context);
//TODO: determine if InsertOnDuplicateKeyUpdateEntities() will work for junctions
//TODO: determine if InsertOnDuplicateKeyUpdate() will work for junctions
}
private static void SeedEntities(DbContext context)
{
Seed<Language>(context);
Seed<License>(context);
Seed<Maintainer>(context);
Seed<Software>(context);
Seed<Syntax>(context);
Seed<FilterList>(context);
SeedIfEmpty<Language>(context);
SeedIfEmpty<License>(context);
SeedIfEmpty<Maintainer>(context);
SeedIfEmpty<Software>(context);
SeedIfEmpty<Syntax>(context);
SeedIfEmpty<FilterList>(context);
}
private static void SeedJunctions(DbContext context)
{
Seed<FilterListLanguage>(context);
Seed<FilterListMaintainer>(context);
Seed<Fork>(context);
Seed<Merge>(context);
Seed<SoftwareSyntax>(context);
SeedIfEmpty<FilterListLanguage>(context);
SeedIfEmpty<FilterListMaintainer>(context);
SeedIfEmpty<Fork>(context);
SeedIfEmpty<Merge>(context);
SeedIfEmpty<SoftwareSyntax>(context);
}
private static void Seed<TEntity>(DbContext dbContext) where TEntity : class
private static void SeedIfEmpty<TEntity>(DbContext dbContext) where TEntity : class
{
if (dbContext.Set<TEntity>().Any()) return;
var rows = GetSeedRows<TEntity>();
@ -58,10 +58,10 @@ private static void Seed<TEntity>(DbContext dbContext) where TEntity : class
dbContext.SaveChanges();
}
private static List<TEntity> GetSeedRows<TEntity>()
private static List<TEntityType> GetSeedRows<TEntityType>()
{
return JsonConvert.DeserializeObject<List<TEntity>>(
File.ReadAllText(SeedDirectory + Path.DirectorySeparatorChar + typeof(TEntity).Name + ".json"));
return JsonConvert.DeserializeObject<List<TEntityType>>(
File.ReadAllText(SeedDirectory + Path.DirectorySeparatorChar + typeof(TEntityType).Name + ".json"));
}
private static void InsertOnDuplicateKeyUpdateEntities(DbContext context)
@ -74,58 +74,50 @@ private static void InsertOnDuplicateKeyUpdateEntities(DbContext context)
InsertOnDuplicateKeyUpdate<FilterList>(context);
}
private static void InsertOnDuplicateKeyUpdate<TEntity>(DbContext dbContext) where TEntity : class
private static void InsertOnDuplicateKeyUpdate<TEntityType>(DbContext dbContext) where TEntityType : 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);
var entityType = dbContext.Model.FindEntityType(typeof(TEntityType));
var properties = GetPropertiesLessValueGeneratedTimestamps(entityType);
var columns = string.Join(", ", properties.Select(x => x.Name));
var values = CreateValues<TEntityType>(properties);
var updates = CreateUpdates(properties);
var rawSqlString = "INSERT INTO " + entityType.Relational().TableName + " (" + columns + ") VALUES " +
values + " ON DUPLICATE KEY UPDATE " + updates;
dbContext.Set<TEntityType>().FromSql(rawSqlString);
dbContext.SaveChanges();
}
private static string GetTableName<TEntity>()
private static List<IProperty> GetPropertiesLessValueGeneratedTimestamps(IEntityType entityType)
{
return typeof(TEntity).Name.Pluralize().ToLower();
return entityType.GetProperties()
.Where(x => x.ClrType != typeof(DateTime) || x.ValueGenerated == ValueGenerated.Never).ToList();
}
private static List<PropertyInfo> GetColumnPropertiesLessBaseEntityTimestamps<TEntity>()
private static string CreateValues<TEntityType>(IReadOnlyCollection<IProperty> columnProperties)
{
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("",
return GetSeedRows<TEntityType>().Select(row => CreateRowValues(columnProperties, row)).Aggregate("",
(current, rowValues) => current == "" ? rowValues : current + ", " + rowValues);
}
private static string CreateRowValues<TEntity>(IEnumerable<PropertyInfo> columnProperties, TEntity row)
private static string CreateRowValues<TEntityType>(IEnumerable<IProperty> properties, TEntityType row)
{
return (from property in columnProperties
return (from property in properties
let value = row.GetType().GetProperty(property.Name).GetValue(row)
select WrapStringPropertyValueInSingleQuotes(property, value)).Aggregate("",
(current, value) => current == "" ? "(" + value : current + ", " + value) + ")";
select WrapStringValueInSingleQuotes(property, value)).Aggregate("",
(rowValues, value) => rowValues == "" ? "(" + value : rowValues + ", " + value) + ")";
}
private static object WrapStringPropertyValueInSingleQuotes(PropertyInfo property, object value)
private static object WrapStringValueInSingleQuotes(IProperty property, object value)
{
if (property.PropertyType == typeof(string))
value = "'" + value + "'";
return value;
return property.ClrType == typeof(string) ? "'" + value + "'" : value;
}
private static string CreateUpdates(IEnumerable<PropertyInfo> columnProperties)
private static string CreateUpdates(IEnumerable<IProperty> properties)
{
//TODO: filter keys out
return columnProperties.Select(property => property.Name).Aggregate("", (current, column) => current == ""
? column + " = VALUES(" + column + ")"
: current + ", " + column + " = VALUES(" + column + ")");
return (from property in properties
where !property.IsPrimaryKey()
select property.Name + " = VALUES(" + property.Name + ")").Aggregate("",
(updates, columnUpdates) => updates == "" ? columnUpdates : updates + ", " + columnUpdates);
}
}
}