Abp: Repository problems

Created on 16 Jan 2020  路  8Comments  路  Source: abpframework/abp

I upgraded from 0.21 to version 2 and this code used to work.

Give this code

   var log = new NotificationLog()
                {
                    TenantId = tenantId,
                };

  log.Details.Add(new NotificationLogDetail()
                        {

                            NotificationType = "Email",
                            NotificationName = template.Event + " (" + template.Role + ")",
                            NotificationTag1 = @event.ContentId.ToString(),
                            To = userInfo.User.Email
                        });

                await _notificationLogRepo.InsertAsync(log);

Throws the following exception
The instance of entity type 'NotificationLogDetail' cannot be tracked because another instance with the key value '{Id: 00000000-0000-0000-0000-000000000000}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

I don't know if this is the intended behavior but I had to change

   public class NotificationLogDetail : CreationAuditedEntity<Guid>
    {
        public string NotificationType { get; set; }
        public string NotificationName { get; set; }

        public string NotificationTag1 { get; set; }
        public string NotificationTag2 { get; set; }


        public string To { get; set; }
    }

to

   public class NotificationLogDetail : CreationAuditedEntity<Guid>
    {
        public override Guid Id { get; protected set; } = Guid.NewGuid(); <------

        public string NotificationType { get; set; }
        public string NotificationName { get; set; }

        public string NotificationTag1 { get; set; }
        public string NotificationTag2 { get; set; }


        public string To { get; set; }
    }

And now it works. Is this the intended behavior or is it a bug? Thank you!

question

Most helpful comment

Yes, set on their constructor (use IGuidGenerator). Not only for nesteds, for all of your entities / aggregate roots.

All 8 comments

@wocar
Maybe you can try it like in below CrudAppService Code:
I think Id should be set by code ,

        protected virtual void SetIdForGuids(TEntity entity)
        {
            var entityWithGuidId = entity as IEntity<Guid>;

            if (entityWithGuidId == null || entityWithGuidId.Id != Guid.Empty)
            {
                return;
            }

            EntityHelper.TrySetId(
                entityWithGuidId,
                () => GuidGenerator.Create(),
                true
            );
        }

by the way, TenantId is the same

        protected virtual void TryToSetTenantId(TEntity entity)
        {
            if (entity is IMultiTenant && HasTenantIdProperty(entity))
            {
                var tenantId = CurrentTenant.Id;

                if (!tenantId.HasValue)
                {
                    return;
                }

                var propertyInfo = entity.GetType().GetProperty(nameof(IMultiTenant.TenantId));

                if (propertyInfo == null || propertyInfo.GetSetMethod(true) == null)
                {
                    return;
                }

                propertyInfo.SetValue(entity, tenantId);
            }
        }

Entities should have a .ctor method to set Id and other properties, please follow abp docs:
https://docs.abp.io/en/abp/latest/Entities#aggregate-example

@gdlcf88
Thanks for remind.
and how about tenantId ,should I set it by ICurrentTenant.Id myself even client is Authorization

and how about tenantId ,should I set it by ICurrentTenant.Id myself even client is Authorization

I will manually set TenantId = ICurrentTenant.Id for new entity, and if you are in ApplicationService or DomainService, the base class property CurrentTenant has been set by abp framework, you do not have to inject it manually.

This is EF Core error I suppose.
Always set GUID Ids as best practice.
See https://github.com/abpframework/abp/blob/dev/docs/en/Entities.md#entities-with-guid-keys

Also, always set TenantId manually (because ABP may not know what was the tenantid when you have created the entity - you know you can change tenantid before save the entity).

Thanks for the reply @hikalkan so bottom line is that I have to set the nested collection鈥檚 items IDs in the constructor?

Did I understand correctly?

Yes, set on their constructor (use IGuidGenerator). Not only for nesteds, for all of your entities / aggregate roots.

Thanks!! Love your work guys keep it up!!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vfabregat picture vfabregat  路  3Comments

hikalkan picture hikalkan  路  3Comments

hikalkan picture hikalkan  路  3Comments

hikalkan picture hikalkan  路  3Comments

hikalkan picture hikalkan  路  3Comments