hi
Can you add some code to the Program
to read and log the AbpLicenseCode
from appsettings.json
Thanks.
hi
AI is right.
You can override the DefaultHttpExceptionStatusCodeFinder
.
https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs#L70-L73
Thanks.
hi
Please use IRemoteStreamContent
to replace IFormFile
in your DTO and regenerate the Angular proxy.
https://abp.io/docs/latest/framework/architecture/domain-driven-design/application-services#working-with-streams
Thanks.
hi
The new version
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers;
public class MyAbpEntityEntry
{
public string Id { get; set; }
public EntityEntry EntityEntry { get; set; }
public List<MyAbpNavigationEntry> NavigationEntries { get; set; }
private bool _isModified;
public bool IsModified
{
get
{
return _isModified || EntityEntry.State == EntityState.Modified || NavigationEntries.Any(n => n.IsModified);
}
set => _isModified = value;
}
public MyAbpEntityEntry(string id, EntityEntry entityEntry)
{
Id = id;
EntityEntry = entityEntry;
NavigationEntries = EntityEntry.Navigations.Select(x => new MyAbpNavigationEntry(x, x.Metadata.Name)).ToList();
}
public void UpdateNavigation(EntityEntry entityEntry, MyAbpNavigationEntry navigationEntry)
{
if (IsModified ||
EntityEntry.State == EntityState.Modified ||
navigationEntry.IsModified)
{
return;
}
var currentValue = navigationEntry.NavigationEntry.CurrentValue;
if (currentValue == null)
{
return;
}
if (navigationEntry.NavigationEntry is CollectionEntry)
{
navigationEntry.OriginalValue!.As<List<object>>().Add(entityEntry.Entity);
}
else
{
navigationEntry.OriginalValue = currentValue;
}
}
}
public class MyAbpNavigationEntry
{
public NavigationEntry NavigationEntry { get; set; }
public string Name { get; set; }
public bool IsModified { get; set; }
public object? OriginalValue { get; set; }
public object? CurrentValue => NavigationEntry.CurrentValue;
public MyAbpNavigationEntry(NavigationEntry navigationEntry, string name)
{
NavigationEntry = navigationEntry;
Name = name;
if (navigationEntry.CurrentValue != null )
{
OriginalValue = navigationEntry is CollectionEntry ? new List<object>() : navigationEntry.CurrentValue;
}
}
}
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(AbpEfCoreNavigationHelper))]
public class MyAbpEfCoreNavigationHelper : AbpEfCoreNavigationHelper
{
protected Dictionary<string, MyAbpEntityEntry> MyEntityEntries { get; } = new();
public override void ChangeTracker_Tracked(object? sender, EntityTrackedEventArgs e)
{
EntityEntryTrackedOrStateChanged(e.Entry);
DetectChanges(e.Entry);
}
public override void ChangeTracker_StateChanged(object? sender, EntityStateChangedEventArgs e)
{
EntityEntryTrackedOrStateChanged(e.Entry);
DetectChanges(e.Entry);
}
protected override void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
{
if (entityEntry.State != EntityState.Unchanged)
{
return;
}
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return;
}
if (MyEntityEntries.ContainsKey(entryId))
{
return;
}
MyEntityEntries.Add(entryId, new MyAbpEntityEntry(entryId, entityEntry));
}
protected override void DetectChanges(EntityEntry entityEntry, bool checkEntityEntryState = true)
{
#pragma warning disable EF1001
var stateManager = entityEntry.Context.GetDependencies().StateManager;
var internalEntityEntityEntry = stateManager.TryGetEntry(entityEntry.Entity, throwOnNonUniqueness: false);
if (internalEntityEntityEntry == null)
{
return;
}
var foreignKeys = entityEntry.Metadata.GetForeignKeys().ToList();
foreach (var foreignKey in foreignKeys)
{
var principal = stateManager.FindPrincipal(internalEntityEntityEntry, foreignKey);
if (principal == null)
{
continue;
}
var entryId = GetEntityEntryIdentity(principal.ToEntityEntry());
if (entryId == null || !MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
continue;
}
var navigationEntry = myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == foreignKey) ??
myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == foreignKey);
if (navigationEntry != null && checkEntityEntryState && entityEntry.State == EntityState.Unchanged)
{
myAbpEntityEntry.UpdateNavigation(entityEntry, navigationEntry);
}
if (!myAbpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry)))
{
myAbpEntityEntry.IsModified = true;
DetectChanges(myAbpEntityEntry.EntityEntry, false);
}
if (navigationEntry != null && IsEntityEntryChanged(entityEntry))
{
navigationEntry.IsModified = true;
}
}
var skipNavigations = entityEntry.Metadata.GetSkipNavigations().ToList();
foreach (var skipNavigation in skipNavigations)
{
var joinEntityType = skipNavigation.JoinEntityType;
var foreignKey = skipNavigation.ForeignKey;
var inverseForeignKey = skipNavigation.Inverse.ForeignKey;
foreach (var joinEntry in stateManager.Entries)
{
if (joinEntry.EntityType != joinEntityType || stateManager.FindPrincipal(joinEntry, foreignKey) != internalEntityEntityEntry)
{
continue;
}
var principal = stateManager.FindPrincipal(joinEntry, inverseForeignKey);
if (principal == null)
{
continue;
}
var entryId = GetEntityEntryIdentity(principal.ToEntityEntry());
if (entryId == null || !MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
continue;
}
var navigationEntry = myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == inverseForeignKey) ??
myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == inverseForeignKey);
if (navigationEntry != null && checkEntityEntryState && entityEntry.State == EntityState.Unchanged)
{
myAbpEntityEntry.UpdateNavigation(entityEntry, navigationEntry);
}
if (!myAbpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry)))
{
myAbpEntityEntry.IsModified = true;
DetectChanges(myAbpEntityEntry.EntityEntry, false);
}
if (navigationEntry != null && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry)))
{
navigationEntry.IsModified = true;
}
}
}
#pragma warning restore EF1001
}
protected override bool IsEntityEntryChanged(EntityEntry entityEntry)
{
return entityEntry.State == EntityState.Added ||
entityEntry.State == EntityState.Deleted ||
entityEntry.State == EntityState.Modified;
}
public override List<EntityEntry> GetChangedEntityEntries()
{
return MyEntityEntries
.Where(x => x.Value.IsModified)
.Select(x => x.Value.EntityEntry)
.ToList();
}
public override bool IsEntityEntryModified(EntityEntry entityEntry)
{
if (entityEntry.State == EntityState.Modified)
{
return true;
}
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return false;
}
return MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry) && myAbpEntityEntry.IsModified;
}
public override bool IsNavigationEntryModified(EntityEntry entityEntry, int? navigationEntryIndex = null)
{
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return false;
}
if (!MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
return false;
}
if (navigationEntryIndex == null)
{
return myAbpEntityEntry.NavigationEntries.Any(x => x.IsModified);
}
var navigationEntryProperty = myAbpEntityEntry.NavigationEntries.ElementAtOrDefault(navigationEntryIndex.Value);
return navigationEntryProperty != null && navigationEntryProperty.IsModified;
}
public override AbpNavigationEntry? GetNavigationEntry(EntityEntry entityEntry, int navigationEntryIndex)
{
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return null;
}
if (!MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
return null;
}
var element = myAbpEntityEntry.NavigationEntries.ElementAtOrDefault(navigationEntryIndex);
if (element == null)
{
return null;
}
return new AbpNavigationEntry(element.NavigationEntry, element.Name)
{
IsModified = element.IsModified,
OriginalValue = element.OriginalValue
};
}
protected override string? GetEntityEntryIdentity(EntityEntry entityEntry)
{
if (entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1)
{
return $"{entityEntry.Metadata.ClrType.FullName}:{entryEntity.GetKeys().FirstOrDefault()}";
}
return null;
}
public override void RemoveChangedEntityEntries()
{
MyEntityEntries.RemoveAll(x => x.Value.IsModified);
}
public override void Clear()
{
MyEntityEntries.Clear();
}
}
Hi
I will create a test project and check the results if you don’t have time to prepare the demo.
Thanks
Hi
I will check if we can refactor this function.
Thanks
Hi
I will check this case with your project.
Thanks
Hi
If you can share a minimal project I can check it, maybe we can improve more performance.
Thanks
hi
Can you try to override the AbpEfCoreNavigationHelper
in your project?
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.EntityFrameworkCore.ChangeTrackers;
public class MyAbpEntityEntry
{
public string Id { get; set; }
public EntityEntry EntityEntry { get; set; }
public List<AbpNavigationEntry> NavigationEntries { get; set; }
private bool _isModified;
public bool IsModified
{
get
{
return _isModified || EntityEntry.State == EntityState.Modified || NavigationEntries.Any(n => n.IsModified);
}
set => _isModified = value;
}
public MyAbpEntityEntry(string id, EntityEntry entityEntry)
{
Id = id;
EntityEntry = entityEntry;
NavigationEntries = EntityEntry.Navigations.Select(x => new AbpNavigationEntry(x, x.Metadata.Name)).ToList();
}
public void UpdateNavigationEntries()
{
foreach (var navigationEntry in NavigationEntries)
{
if (IsModified ||
EntityEntry.State == EntityState.Modified ||
navigationEntry.IsModified ||
navigationEntry.NavigationEntry.IsModified)
{
continue;
}
var currentValue = AbpNavigationEntry.GetOriginalValue(navigationEntry.NavigationEntry.CurrentValue);
if (currentValue == null)
{
continue;
}
switch (navigationEntry.OriginalValue)
{
case null:
navigationEntry.OriginalValue = currentValue;
break;
case IEnumerable originalValueCollection when currentValue is IEnumerable currentValueCollection:
{
var existingList = originalValueCollection.Cast<object?>().ToList();
var newList = currentValueCollection.Cast<object?>().ToList();
if (newList.Count > existingList.Count)
{
navigationEntry.OriginalValue = currentValue;
}
break;
}
default:
navigationEntry.OriginalValue = currentValue;
break;
}
}
}
}
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(AbpEfCoreNavigationHelper))]
public class MyAbpEfCoreNavigationHelper : AbpEfCoreNavigationHelper
{
protected Dictionary<string, MyAbpEntityEntry> MyEntityEntries { get; } = new();
public override void ChangeTracker_Tracked(object? sender, EntityTrackedEventArgs e)
{
EntityEntryTrackedOrStateChanged(e.Entry);
DetectChanges(e.Entry);
}
public override void ChangeTracker_StateChanged(object? sender, EntityStateChangedEventArgs e)
{
EntityEntryTrackedOrStateChanged(e.Entry);
DetectChanges(e.Entry);
}
protected override void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
{
if (entityEntry.State != EntityState.Unchanged)
{
return;
}
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return;
}
if (MyEntityEntries.ContainsKey(entryId))
{
return;
}
MyEntityEntries.Add(entryId, new MyAbpEntityEntry(entryId, entityEntry));
}
protected override void DetectChanges(EntityEntry entityEntry, bool checkEntityEntryState = true)
{
#pragma warning disable EF1001
var stateManager = entityEntry.Context.GetDependencies().StateManager;
var internalEntityEntityEntry = stateManager.TryGetEntry(entityEntry.Entity, throwOnNonUniqueness: false);
if (internalEntityEntityEntry == null)
{
return;
}
var foreignKeys = entityEntry.Metadata.GetForeignKeys().ToList();
foreach (var foreignKey in foreignKeys)
{
var principal = stateManager.FindPrincipal(internalEntityEntityEntry, foreignKey);
if (principal == null)
{
continue;
}
var entryId = GetEntityEntryIdentity(principal.ToEntityEntry());
if (entryId == null || !MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
continue;
}
myAbpEntityEntry.UpdateNavigationEntries();
if (!myAbpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry)))
{
myAbpEntityEntry.IsModified = true;
DetectChanges(myAbpEntityEntry.EntityEntry, false);
}
var navigationEntry = myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == foreignKey) ??
myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == foreignKey);
if (navigationEntry != null && IsEntityEntryChanged(entityEntry))
{
navigationEntry.IsModified = true;
}
}
var skipNavigations = entityEntry.Metadata.GetSkipNavigations().ToList();
foreach (var skipNavigation in skipNavigations)
{
var joinEntityType = skipNavigation.JoinEntityType;
var foreignKey = skipNavigation.ForeignKey;
var inverseForeignKey = skipNavigation.Inverse.ForeignKey;
foreach (var joinEntry in stateManager.Entries)
{
if (joinEntry.EntityType != joinEntityType || stateManager.FindPrincipal(joinEntry, foreignKey) != internalEntityEntityEntry)
{
continue;
}
var principal = stateManager.FindPrincipal(joinEntry, inverseForeignKey);
if (principal == null)
{
continue;
}
var entryId = GetEntityEntryIdentity(principal.ToEntityEntry());
if (entryId == null || !MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
continue;
}
myAbpEntityEntry.UpdateNavigationEntries();
if (!myAbpEntityEntry.IsModified && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry)))
{
myAbpEntityEntry.IsModified = true;
DetectChanges(myAbpEntityEntry.EntityEntry, false);
}
var navigationEntry = myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is INavigation navigationMetadata && navigationMetadata.ForeignKey == inverseForeignKey) ??
myAbpEntityEntry.NavigationEntries.FirstOrDefault(x => x.NavigationEntry.Metadata is ISkipNavigation skipNavigationMetadata && skipNavigationMetadata.ForeignKey == inverseForeignKey);
if (navigationEntry != null && (!checkEntityEntryState || IsEntityEntryChanged(entityEntry)))
{
navigationEntry.IsModified = true;
}
}
}
#pragma warning restore EF1001
}
protected override bool IsEntityEntryChanged(EntityEntry entityEntry)
{
return entityEntry.State == EntityState.Added ||
entityEntry.State == EntityState.Deleted ||
entityEntry.State == EntityState.Modified;
}
public override List<EntityEntry> GetChangedEntityEntries()
{
return MyEntityEntries
.Where(x => x.Value.IsModified)
.Select(x => x.Value.EntityEntry)
.ToList();
}
public override bool IsEntityEntryModified(EntityEntry entityEntry)
{
if (entityEntry.State == EntityState.Modified)
{
return true;
}
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return false;
}
return MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry) && myAbpEntityEntry.IsModified;
}
public override bool IsNavigationEntryModified(EntityEntry entityEntry, int? navigationEntryIndex = null)
{
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return false;
}
if (!MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
return false;
}
if (navigationEntryIndex == null)
{
return myAbpEntityEntry.NavigationEntries.Any(x => x.IsModified);
}
var navigationEntryProperty = myAbpEntityEntry.NavigationEntries.ElementAtOrDefault(navigationEntryIndex.Value);
return navigationEntryProperty != null && navigationEntryProperty.IsModified;
}
public override AbpNavigationEntry? GetNavigationEntry(EntityEntry entityEntry, int navigationEntryIndex)
{
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return null;
}
if (!MyEntityEntries.TryGetValue(entryId, out var myAbpEntityEntry))
{
return null;
}
return myAbpEntityEntry.NavigationEntries.ElementAtOrDefault(navigationEntryIndex);
}
protected override string? GetEntityEntryIdentity(EntityEntry entityEntry)
{
if (entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1)
{
return $"{entityEntry.Metadata.ClrType.FullName}:{entryEntity.GetKeys().FirstOrDefault()}";
}
return null;
}
public override void RemoveChangedEntityEntries()
{
MyEntityEntries.RemoveAll(x => x.Value.IsModified);
}
public override void Clear()
{
MyEntityEntries.Clear();
}
}