internal static IQueryable <TEntity> GetTranslatedQuery <TEntity>(this IQueryable <TEntity> query, object[] desiredLanguageKey, object[] defaultLanguageKey, Expression <Func <TEntity, bool> > predicate = null) where TEntity : class { var context = PersistenceHelpers.GetDbContext(query); var translationEntity = TranslationConfiguration.TranslationEntities[typeof(TEntity).FullName]; PersistenceHelpers.ValidateLanguageKeys(translationEntity.KeysFromLanguageEntity, desiredLanguageKey, defaultLanguageKey); var baseQuery = context.GetType() .GetMethod("Query") .MakeGenericMethod(translationEntity.Type); var defaultTranslationQuery = (IQueryable <object>)baseQuery.Invoke(context, null); var desiredTranslationQuery = (IQueryable <object>)baseQuery.Invoke(context, null); int parameterPosition = 0; foreach (var property in translationEntity.KeysFromLanguageEntity) { defaultTranslationQuery = defaultTranslationQuery.Where(BuildPredicate(property.Name, defaultLanguageKey[parameterPosition])); desiredTranslationQuery = desiredTranslationQuery.Where(BuildPredicate(property.Name, desiredLanguageKey[parameterPosition])); parameterPosition++; } var sourceKeys = translationEntity.KeysFromSourceEntity.Select(key => key.Key); var relationshipKeys = translationEntity.KeysFromSourceEntity.Select(key => key.Value); if (predicate != null) { query = query.Where(predicate); } var wanted = query //Fallback .Join( defaultTranslationQuery, GetKeys <TEntity>(sourceKeys), GetKeys <object>(relationshipKeys), (Entity, Translation) => new QueryJoinHelper <TEntity> { Entity = Entity, Translation = Translation }) //Wanted .GroupJoin( desiredTranslationQuery, GetKeysFromGroup <QueryJoinHelper <TEntity>, TEntity>(sourceKeys), GetKeys <object>(relationshipKeys), (Base, Translation) => new { Base, Translation }) .SelectMany(result => result.Translation.DefaultIfEmpty(), (From, Translation) => From.Base.Entity.SetTranslatedProperties(Translation ?? From.Base.Translation)); return(wanted); }
//■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ internal static async Task <List <dynamic> > GetAllTranslationsQuery <TEntity>(this IQueryable <TEntity> query, CancellationToken cancellationToken = default) where TEntity : class { var context = PersistenceHelpers.GetDbContext(query); var translationEntity = TranslationConfiguration.TranslationEntities[typeof(TEntity).FullName]; var ingredients = await query.ToListAsync(cancellationToken); var sourceKeys = translationEntity.KeysFromSourceEntity.Select(key => key.Key); var relationshipKeys = translationEntity.KeysFromSourceEntity.Select(key => key.Value); var ingredientsTranslations = await query .Join( context.GetType().GetMethod("Query").MakeGenericMethod(translationEntity.Type).Invoke(context, null) as IQueryable <object>, GetKeys <TEntity>(sourceKeys), GetKeys <object>(relationshipKeys), (Entity, Translation) => Translation) .ToListAsync(cancellationToken); var translatedIngredients = new List <dynamic>(); foreach (var ingredient in ingredients) { IDictionary <string, object> ingredientMapping = new ExpandoObject(); foreach (var property in typeof(TEntity).GetProperties()) { if (translationEntity.Type.GetProperty(property.Name) != null) { var translations = new Dictionary <object, string>(); var currentIngredientTranslations = ingredientsTranslations.AsQueryable(); foreach (var keyFromSource in translationEntity.KeysFromSourceEntity) { currentIngredientTranslations = currentIngredientTranslations .Where(translation => context .Entry(translation) .Property(keyFromSource.Value).CurrentValue .Equals(ingredient.GetType().GetProperty(keyFromSource.Key).GetValue(ingredient))); } foreach (var translation in currentIngredientTranslations) { var languageKey = new Dictionary <string, object>(); foreach (var languageProperty in translationEntity.KeysFromLanguageEntity) { languageKey.Add(languageProperty.Name, context.Entry(translation).Property(languageProperty.Name).CurrentValue); } if (languageKey.Count == 1) { translations.Add(languageKey.First().Value, translation.GetType().GetProperty(property.Name).GetValue(translation) as string); } else { translations.Add(languageKey, translation.GetType().GetProperty(property.Name).GetValue(translation) as string); } } ingredientMapping.Add($"{property.Name}Translations", translations); } else { ingredientMapping.Add(property.Name, property.GetValue(ingredient)); } } translatedIngredients.Add(ingredientMapping); } return(translatedIngredients); }
//═════════════════════════════════════════════════════════════════════════════════════════ public static void UpsertTranslationRange <TEntity>([NotNull] this IQueryable <TEntity> source, TEntity entity, params Translation <TEntity>[] translationEntities) where TEntity : class { int parameterPosition; var context = PersistenceHelpers.GetDbContext(source); var translationEntity = TranslationConfiguration.TranslationEntities[typeof(TEntity).FullName]; var method = getExistingTranslationsMethod.MakeGenericMethod(typeof(TEntity), translationEntity.Type); IEnumerable <IDictionary <string, object> > existingTranslations = null; PersistenceHelpers.ValidateLanguageKeys(translationEntity.KeysFromLanguageEntity, translationEntities.SelectMany(translation => translation.LanguageKey).ToArray()); foreach (var entry in translationEntities) { var translation = Activator.CreateInstance(translationEntity.Type); var trackedEntity = context.ChangeTracker.Entries().Where(entry => entry.Entity.GetType() == translationEntity.Type); foreach (var property in entry.Entity.GetType().GetProperties()) { translationEntity.Type.GetProperty(property.Name)?.SetValue(translation, property.GetValue(entry.Entity)); } parameterPosition = 0; foreach (var property in translationEntity.KeysFromLanguageEntity) { context.Entry(translation).Property(property.Name).CurrentValue = entry.LanguageKey[parameterPosition]; trackedEntity = trackedEntity.Where(entry => entry.Property(property.Name).CurrentValue.Equals(context.Entry(translation).Property(property.Name).CurrentValue)); parameterPosition++; } foreach (var property in translationEntity.KeysFromSourceEntity) { context.Entry(translation).Property(property.Value).CurrentValue = entity.GetType().GetProperty(property.Key).GetValue(entity); trackedEntity = trackedEntity.Where(entry => entry.Property(property.Value).CurrentValue.Equals(context.Entry(translation).Property(property.Value).CurrentValue)); } var tracked = trackedEntity.SingleOrDefault(); if (tracked != null) { foreach (var property in tracked.Entity.GetType().GetProperties() .Where(property => !translationEntity.KeysFromLanguageEntity.Select(key => key.Name).Contains(property.Name) || !translationEntity.KeysFromSourceEntity.Select(key => key.Value).Contains(property.Name))) { tracked.Property(property.Name).CurrentValue = context.Entry(translation).Property(property.Name).CurrentValue; } } else { existingTranslations ??= ((IEnumerable <IDictionary <string, object> >)method.Invoke(null, new object[] { context, entity, translationEntity, translationEntities })).ToList(); var existingTranslation = existingTranslations.AsQueryable(); foreach (var property in context.Entry(translation).Properties .Where(property => translationEntity.KeysFromLanguageEntity.Select(key => key.Name).Contains(property.Metadata.Name) || translationEntity.KeysFromSourceEntity.Select(key => key.Value).Contains(property.Metadata.Name))) { existingTranslation = existingTranslation.Where(translation => translation[property.Metadata.Name].Equals(property.CurrentValue)); } if (existingTranslation.Count() > 0) { context.Entry(translation).State = EntityState.Modified; } else { context.Entry(translation).State = EntityState.Added; } } } }