Base solution for your next web application
Open Closed

Entity History new issue #12333


User avatar
0
uenlkr4e created

Hi,

i have entity history enabled for TenantCredit.

I do update TenantCredit in host level but i want tenant to see the history.

Since i do it at the host level, tenant id is set to null in history tables so only host can see the history.

So i decided to set the tenantId as such while performing the update operation.

using (CurrentUnitOfWork.SetTenantId(tenantCredit.TenantId))
            {
                tenantCredit.RemainingCredit = input.Credit;
                tenantCredit.IsActive = true;
                await _tenantCreditRepository.InsertAsync(tenantCredit);
            }

for some reason this doesnt set the tenant id in entity change sets and entity property changes tables, they are still null.
am i doing something wrong?

thank you


10 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Could you wrap your code using https://aspnetboilerplate.com/Pages/Documents/Abp-Session#user-identifier and see if it works ?

  • User Avatar
    0
    uenlkr4e created

    Hi,
    yes this seems to set the tenantId i want but there is still a problem with entity history.

    is it not possible for tenant to see the update history performed by the host?
    In my case host creates credit for the tenant and also updates this credit.

    how can i show the credit history to tenant?

    even though the tenant id is successfully set using your suggestion, the tenant can still not see the history because of the following line probably: join user in _userRepository.GetAll() on entityChangeSet.UserId equals user.Id

    a regular join is made to user table and tenant filter is applied so the history is not fetched either.

    There has to be an easy way to accomplish this.
    any suggestions?

    thanks

  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @uenlkr4e

    Here you want to list the changes made by the Host with the entity in the Tenant you specified. Here you need to do the following: All changes made with the relevant tenant on the Host side will be listed, you need to list them without filtering in the current listing query. While bringing the Entity History information in the Change Logs table, if the Host is a user, you need to list them without filtering the Tenant. At the same time, you can use the code you set for the Tenant Id when determining credit for the Tenant you specified.

    Example:

    You need to make this setting only for the host user.

    using (_unitOfWorkManager.Current.SetTenantId(null))
    {
     //EntityChanges query should be included here
    }
    

    Your code:

    You can use this setting when defining credit.

    using (CurrentUnitOfWork.SetTenantId(tenantCredit.TenantId))
    {
        tenantCredit.RemainingCredit = input.Credit;
        tenantCredit.IsActive = true;
        await _tenantCreditRepository.InsertAsync(tenantCredit);
    }
    

    Thus, an identification is made according to the specified tenantid and this change is reflected in the entity changes information of both the Host user and the Tenant user.

  • User Avatar
    0
    uenlkr4e created

    Hi @oguzhanagir,
    thanks for the answer but there are a couple issue here:

    1. using (CurrentUnitOfWork.SetTenantId(tenantCredit.TenantId)) did not work so i had to try what ismcagdas suggested and it set the tenantId as i expected. BUT

    2. Even after setting the tenantId correctly Tenant can still not see the Entity history logs because there is UserId in logs and UserId belongs to Host since host inserted/updated the tenantCredit entity. With this suggested solution both host and tenant can not see the entity history since logs have tenant Id but the User belongs to Host.
      Here is the query in GetEntityTypeChanges method:

    var query = from entityChangeSet in _entityChangeSetRepository.GetAll()
                            join entityChange in _entityChangeRepository.GetAll() on entityChangeSet.Id equals entityChange.EntityChangeSetId
                            **join user in _userRepository.GetAll() on entityChangeSet.UserId equals user.Id**
                            where entityChange.EntityTypeFullName == input.EntityTypeFullName &&
                                  (entityChange.EntityId == input.EntityId || entityChange.EntityId == entityId)
                            select new EntityChangeAndUser
                            {
                                EntityChange = entityChange,
                                User = user
                            };
    

    I dont want to change your GetEntityTypeChanges method.

    any other suggestions?

  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @uenlkr4e

    This suggested method was working according to your scenario. Could you please send your project to support@aspnetzero.com so that we can provide you with a more accurate solution?

  • User Avatar
    0
    uenlkr4e created

    I cant share the full project but i will try to get something together.

    With your suggested solution tenantid is set to 1 in my system and the userid is also set to 1.
    but userId 1 is not a user of tenant id 1.

    userid 1 is a host user.

    does your solution bring up such records?
    history belongs to a tenant but its user belongs to host.

    how did you overcome this problem in your case?

  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @uenlkr4e

    Here, if you want to reflect only the relevant tenant when an entity belonging to a tenant changes, it will be enough to set the TenantId as Current. After setting the relevant TenantId while defining a loan, only that relevant Tenant will be reflected in the Change Logs table. Here, it will not be reflected in the Host. Since you want to reflect it to the Host user, you can create a separate AppService method and set the TenantId as null in the entityChanges query. Now, the changes belonging to the tenants will be listed in this query.

    In this solution, it does not filter by User, but by Tenant. If you want to filter by User, it will be enough to use only UserId.

  • User Avatar
    0
    uenlkr4e created

    Hi,
    thank you for the response.

    I think we have a misunderstanding here. When a host user updates something that belongs to a tenant, i want tenant to see this change under entity history.
    So yes setting the relevant tenant as current sets the tenantId correctly instead of setting it null since a host user caused the history creation.
    But because of the code i shared above (that is abp's code, i didnt write it), tenant can not see this history record because the code creates a join to User table using the userId in EntityChangeSet.
    When the tenant calls this code, the user join runs but the user is auto filtered by tenantId (it has imusthave tenant interface definition).

    So tenant can not see this record even though the records tenantId is correct.

    Do i make sense?

    Here is abp's code again: look at the 4th line that goes "join user in ..."

     var query = from entityChangeSet in _entityChangeSetRepository.GetAll()
                            join entityChange in _entityChangeRepository.GetAll() on entityChangeSet.Id equals entityChange.EntityChangeSetId
                            **join user in _userRepository.GetAll() on entityChangeSet.UserId equals user.Id**
                            where entityChange.EntityTypeFullName == input.EntityTypeFullName &&
                                  (entityChange.EntityId == input.EntityId || entityChange.EntityId == entityId)
                            select new EntityChangeAndUser
                            {
                                EntityChange = entityChange,
                                User = user
                            };
    
  • User Avatar
    0
    uenlkr4e created

    It only works if i update the join into a left join, otherwise it wont work because if the problem i tried explaining above.

    works this way but doesnt show the user:

    var query = from entityChangeSet in _entityChangeSetRepository.GetAll()
                            join entityChange in _entityChangeRepository.GetAll() on entityChangeSet.Id equals entityChange.EntityChangeSetId
                            join user in _userRepository.GetAll() on entityChangeSet.UserId equals user.Id into userJoin
                            where entityChange.EntityTypeFullName == input.EntityTypeFullName &&
                                  (entityChange.EntityId == input.EntityId || entityChange.EntityId == entityId)
                            from user in userJoin.DefaultIfEmpty()
                            select new EntityChangeAndUser
                            {
                                EntityChange = entityChange,
                                User = user
                            };
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Sorry for our late reply. If a record has TenantId=NULL (which means HOST), a tenant can't access this record by default. If you want to show such kind of records, you can disable MultiTenancyFilter, see https://aspnetboilerplate.com/Pages/Documents/Data-Filters#disable-filters.

    Then, you can add a filter manually like x.TenantId = {TenantId} || x.TenantId == null