Activities of "maliming"

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();
    }
}

: )

Showing 751 to 760 of 10683 entries
Learn More, Pay Less
33% OFF
All Trainings!
Get Your Deal
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on September 16, 2025, 10:35