Starts in:
2 DAYS
0 HR
2 MIN
35 SEC
Starts in:
2 D
0 H
2 M
35 S

Activities of "selinkoykiran"

Hello, Actually, yes we can override easily :) We don't do another request like you mentioned :) For example:

In this example, we are filtering the tenants just with activation state , it returns 1 record (which is true in our case , because we have only 1 record with that activation state in the db) , because of the total count which is 3 (because of GetCountAsync() filtering issue) , our datatable's and paging is just going crazy.

So , we can override of course , but what do you think about this specific example ? Is it right when you have paging and you're filtering the records you have totally 3 records from the count but the real count is 1 so you are expecting 2 more records because max count is 10 ? What do you think ?

By the way , if I change configuration simply like below : it's working again

So , global configuration is just necessary from abp hangfire implementation side, I think it's because of the below implementation that AbpHangfireOptions itself doesn't add anything.

Thank you.

Hello , So , in that case abp's default async periodic workers like (Token CleanUp Background worker) need that global configuration right ?
If we want to create background jobs or workers (recurring things) which should be working with Hangfire server, we need to configure this global configuration ? AbpHangfireOptions is just for Hangfire server itself , but it is not including jobs or workers working with this server ? Thank you.

Hello , Thanks, It looks like the JobStorage error is gone. But why do we need a global configuration, I had already given the storage configuration with AbpHangfireOptions ?

Hello , I've tried from scratch with brand new abp project and I'm getting still same exception. I specially wanted to try in a template project, because there is nothing special , I've implemented configuration and I'm still getting JobStorage error which I shouldn't take. I think there is a problem about Abp Hangfire BackgroundWorker module or it could be related with Abp Background Job Module. Because I think there are some pre initialized background jobs and handlers' running behind by abp and this async jobs can't work with abp hangfire worker ?

I'm sharing my steps : 1- Firstly I created a new tiered application template project from abp suit with 5.2.0-rc.2 version 2- I installed <PackageReference Include="Volo.Abp.HangFire" Version="5.2.0-rc.2" /> and <PackageReference Include="Volo.Abp.BackgroundWorkers.Hangfire" Version="5.2.0-rc.2" /> references into IdentityServer project. 3- Then I made below configuration inside IdentityServerModule 4- After I ran IdentityServer solution I got below exception :

2022-03-28 13:13:25.938 +03:00 [FTL] deneme52.IdentityServer terminated unexpectedly! Volo.Abp.AbpInitializationException: An error occurred during the initialize Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor phase of the module Volo.Abp.IdentityServer.AbpIdentityServerDomainModule, Volo.Abp.IdentityServer.Domain, Version=5.2.0.0, Culture=neutral, PublicKeyToken=null: JobStorage.Current property value has not been initialized. You must set it before using Hangfire Client or Server API.. See the inner exception for details. ---> System.InvalidOperationException: JobStorage.Current property value has not been initialized. You must set it before using Hangfire Client or Server API. at Hangfire.JobStorage.get_Current() at Hangfire.RecurringJobManager..ctor() at Hangfire.RecurringJob.<>c.<.cctor>b__20_0() at System.Lazy1.CreateValue() at System.Lazy1.get_Value() at Hangfire.RecurringJob.AddOrUpdate(Expression`1 methodCall, String cronExpression, TimeZoneInfo timeZone, String queue) at Volo.Abp.BackgroundWorkers.Hangfire.HangfireBackgroundWorkerManager.AddAsync(IBackgroundWorker worker) at Volo.Abp.IdentityServer.AbpIdentityServerDomainModule.OnApplicationInitializationAsync(ApplicationInitializationContext context) at Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor.InitializeAsync(ApplicationInitializationContext context, IAbpModule module) at Volo.Abp.Modularity.ModuleManager.InitializeModulesAsync(ApplicationInitializationContext context) --- End of inner exception stack trace --- at Volo.Abp.Modularity.ModuleManager.InitializeModulesAsync(ApplicationInitializationContext context) at Volo.Abp.AbpApplicationBase.InitializeModulesAsync() at Volo.Abp.AbpApplicationWithExternalServiceProvider.InitializeAsync(IServiceProvider serviceProvider) at Microsoft.AspNetCore.Builder.AbpApplicationBuilderExtensions.InitializeApplicationAsync(IApplicationBuilder app) at deneme52.Program.Main(String[] args) in C:\Users\z0046r5w\Downloads\deneme52\src\deneme52.IdentityServer\Program.cs:line 40

Thank you.

Hello , (sorry for my late response, I was dealing with another issue. ) Thanks for your suggestions and I've checked your solution and I applied all unit of work depended options. But it just didn't work. After that I saw your ISoftDelete implementation in the framework code in AbpContext :

and I suspect of using of ISoftDelete interface (because like I mentioned before, I couldn't see the change of the entity state as deleted in our case) , so I just removed ISoftDelete interface from our child entities and all the above code that I've mentioned, worked successfully, All child entities removed without removing parent like we expect.

I don't know the main issue, but I think maybe there could be an entity state changing problem about ISoftDelete implementation in such specific cases like ours.

Thank you.

Hello , Is there any progress about this issue ? It is an important problem for us. Thank you.

Of course , could be , Here are our configurations :

**OdmsDbContextModelCreatingExtensions inside: **

            /* Configure all entities here. */
            builder.Entity<Model>(b =>
            {
                b.ToTable(OdmsDbProperties.DbTablePrefix + "Models", OdmsDbProperties.DbSchema);
                b.ConfigureByConvention();
                b.Property(x => x.SchemaName).HasMaxLength(ModelConsts.MaxSchemaNameLength).HasColumnName(nameof(Model.SchemaName)).IsRequired();
                b.Property(x => x.ServerName).HasMaxLength(ModelConsts.MaxServerNameLength).HasColumnName(nameof(Model.ServerName)).IsRequired();
                b.Property(x => x.DatabaseType).HasMaxLength(ModelConsts.MaxDatabaseTypeLength).HasColumnName(nameof(Model.DatabaseType));
                b.Property(x => x.Password).HasMaxLength(ModelConsts.MaxEncryptedPasswordLength).HasColumnName(nameof(Model.Password));
                b.Property(x => x.Version).HasMaxLength(ModelConsts.MaxVersionLength).HasColumnName(nameof(Model.Version));
                // Relations
                b.HasMany<Export>(m => m.Exports).WithOne(e => e.Model).HasForeignKey(e => e.ModelId).IsRequired();
                b.HasMany<Import>(m => m.Imports).WithOne(i => i.Model).HasForeignKey(i => i.ModelId).IsRequired();
                b.HasMany<Source>(m => m.Sources).WithOne(s => s.Model).HasForeignKey(s => s.ModelId).IsRequired();
                // Index
                b.HasIndex(x => new { x.SchemaName });
                b.Navigation(x => x.Exports).HasField("_exports");
                b.Metadata.FindNavigation("Exports").SetPropertyAccessMode(PropertyAccessMode.Field);
                
            });

            builder.Entity<Export>(b =>
            {
                b.ToTable(OdmsDbProperties.DbTablePrefix + "Exports", OdmsDbProperties.DbSchema);
                b.ConfigureByConvention();
                b.Property(x => x.ModelId).HasColumnName(nameof(Export.ModelId)).IsRequired();
                b.Property(x => x.OperationId).HasColumnName(nameof(Export.OperationId)).IsRequired();
                b.Property(x => x.ExportType).HasMaxLength(ExportConsts.MaxExportTypeLength).HasColumnName(nameof(Export.ExportType)).IsRequired();
                b.Property(x => x.Result).HasMaxLength(ExportConsts.MaxResultLength).HasColumnName(nameof(Export.Result)).IsRequired();
                // Value object
                b.OwnsOne(x => x.ExportFile, p =>
                {
                    p.Property(x => x.StorageId).HasColumnName(ExportConsts.ExportFileIdColumnName);
                    p.Property(x => x.Name).HasColumnName(ExportConsts.ExportFileNameColumnName);
                    p.Ignore(x => x.NameOnly);
                    p.Ignore(x => x.FullName);
                    p.Ignore(x => x.ModelType);
                    // Index
                    p.HasIndex(x => x.Name);
                }).Navigation(x => x.ExportFile).IsRequired();

                  
            });

**Domain Manager layer inside : **

        public virtual async Task HardDeleteExportAsync(string schemaName, string serverName, Guid fileId)
        {
            Check.NotNullOrWhiteSpace(schemaName, nameof(schemaName), ModelConsts.MaxSchemaNameLength);
            Check.NotNullOrWhiteSpace(serverName, nameof(serverName), ModelConsts.MaxServerNameLength);

            // Get model from database with conditional exports 
            var model = await ModelRepository.FindWithExportDetailAsync(
                schemaName,
                serverName,
                x => x.IsDeleted == true && x.ExportFile.StorageId == fileId,
                includeDetails: true // includeDetails: Set true to include all children of this aggregate
            );

            if (model == null)
            {
                throw new ModelDoesNotExistException(
                    schemaName: schemaName,
                    serverName: serverName
                );
            }

            //NOTE => below code not working if we have a cascade delete relation but we want to delete only children , not with parent. we need to do it from repository layer
            model.RemoveAllExports(); //model.HardDeleteExport(fileId);

            await ModelRepository.UpdateAsync(model,true);
        }

FindWithExportDetailAsync inside which is inside repository layer :

        public virtual async Task<Model> FindWithExportDetailAsync(string schemaName, string serverName, Expression<Func<Export, bool>> expression, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            return await (await GetDbSetAsync())
                .IncludeExportDetail(expression, includeDetails)  // Include only exports
                .Where(x => x.SchemaName == schemaName && x.ServerName == serverName)
                .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); // Returns null if not found
        }

IncludeExportDetail method inside :


        public static IQueryable<Model> IncludeExportDetail(this IQueryable<Model> queryable, Expression<Func<Export, bool>> predicate, bool include = true)
        {
            if (!include)
            {
                return queryable;
            }

            return queryable
                .Include(
                x => x.Exports.AsQueryable()
                .Where(predicate));
        }```

Model aggregate root and removeExport method

public class Model : AuditedAggregateRoot<Guid>, IMultiTenant // Using Guid type as the Id key
{
    public Guid? TenantId { get; protected set; }

    [NotNull]
    public virtual string SchemaName { get; protected set; } // Value object can be created for primitive types. There is no such requirement in the web API. Inputs are validated in the HTTP layer.

    [NotNull]
    public virtual string ServerName { get; protected set; } // Value object can be created for primitive types. There is no such requirement in the web API. Inputs are validated in the HTTP layer.

    public virtual DatabaseType DatabaseType { get; protected set; }

    public virtual string Password { get; protected set; }

    [NotNull]
    public virtual string Version { get; protected set; }

    // Don't expose mutable collections in an aggregate
    public virtual IReadOnlyCollection<Export> Exports
    {
        get
        {
            return _exports?.ToList(); // Paged operation may return without sub collection. If null then do not turn into list 
        }
    }

    private readonly ICollection<Export> _exports;

    public virtual void RemoveAllExports()
    {
        // NOTE => Clear ,or new, or removeall not working when dealing with ef core because of it only clear the list , and parent doesn't know about the relational children deletion.
        _exports.Clear();
    }
    }

Yes, you should already update the aggregate root normally after children entities changes. So I've tried and that's the problem which is not working even if updating aggregate root. I don't think it's because of private field because we are using backing fields actually , and in a normal ef core project it's working as expected for example :

Aggregate

Entity:

And the operation below is working :

Because of this simple ef core project is working without problem , we think that if this issue about abp efcore implementation? I can show our configuration anytime , adding and saving changes working perfectly but in deletion , removing step with that backing fields , could it be an issue ?

Don't understand the last message , you'll be checking the issue right ?

Showing 11 to 20 of 47 entries
Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06