0

I have stucked with a problem to add UserId property from my ApplicationUser to domain Player entity.

This is my domain entity Player, where I have virtual ApplicationUserId property. I had an idea to write UserId after I created User in UserService, but could't proceed because of protection level of setter. Should I change remove protection level or there is another approach to achive result?

Maybe I should create a method in domain like SetUserId where I will set private property with UserId came from IdentityServer.CreateUser? Does it good approach?

public class Player: MyEntity
    {
        public string UserName { get; private set; }

        public virtual Guid ApplicationUserId { get; private set; }

        private Player() 
        { }

      
    }

UserService.cs snippet where user is creating

public async Task<(AppSignInResult result, SignInData data)> CreateUser(string username, string password, string email, string country)
        {
            var user = new ApplicationUser() { UserName = username, Email = email};

            var result = await _userManager.CreateAsync(user, password);

          ...
             // here is call of mediatr command

            var command = new CreatePlayerCommand(username, country);

           var id = await _mediator.Send(command);

         ...

            return ...
        }

CreatePlayerCommand.Handle handler code

  public async Task<int> Handle(CreatePlayerCommand request, CancellationToken cancellationToken)
           {
               var player = new Player(
                   request.userName);

               _unitOfWork.Players.Add(player);
               await _unitOfWork.SaveChanges();

               return player.Id;
           }
hoozr
  • 403
  • 4
  • 15

3 Answers3

1

Why do you need to set Player.ApplicationUserId? You can generate it in the constructor or in DB. Why do you change the Id? If you access only from CreateUser command, you don't need it. Because the id is not coming from the client. You should generate automatically like that:

Player(string userName, ...)
{     
    ApplicationUserId = Guid.NewGuid();
    UserName = userName;
    ...

}
Tolga Cakir
  • 725
  • 1
  • 7
  • 13
  • But I have already Id created from _userManager.CreateAsync method and it is stored in DB in AspNetUsers table as primary key. I need 1:1 relation for AspNetUser <-> Player. – hoozr Sep 29 '21 at 12:12
  • Still, you don't need to set the ApplicationUserId property anywhere. see: https://stackoverflow.com/questions/42573214/why-to-have-private-setter-in-entity – Tolga Cakir Sep 29 '21 at 12:22
  • 1
    I've achieved your suggestion simply by placing command for domain Player creation before _userManager.CreateUser and created ApplicationUser object with Id = guid created in Player constructor. And it worked! – hoozr Sep 29 '21 at 12:25
  • One more question, If I will change my Id type from Guid to int and I can't create like Guid.NewGuid();? Should I just pass it to constructor parameters and do like this ? Player(..., int userId) { ApplicationUserId = userId} – hoozr Sep 29 '21 at 12:40
  • If you use Id as an integer, you should set auto-increment integer from the database. Then you don't need to change anything on the application side other than to change Id type. Getting an Id from the client-side when creating an entity is not good practice if your id is not meaningful like a GSM number or email or citizenship number. – Tolga Cakir Sep 29 '21 at 12:44
  • Also, Ef core can handle this issue automatically. see: https://learn.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations#primary-keys – Tolga Cakir Sep 29 '21 at 12:53
0

I've created method in domain entity

 private void SetUserId(Guid userId)
        {
            ApplicationUserId = userId;
        }

And passing in CreatePlayerCommand and passing user id from _userManager.CreateAsync result. It works like desired.

hoozr
  • 403
  • 4
  • 15
  • Gonna pass string here and proceed validation of parsing this string -> guid to keep DDD approach. Any thoughts? – hoozr Sep 29 '21 at 11:55
0

Although there's no best idea for this sort of issue, this one could be designed like _buyerId in order class. Please see the link first.

_buyerId should be set in order class because it's a private field. Also, for persisting _buyerId by EF, for example, it could be configured in orderConfiguration.

Ali Soltani
  • 9,589
  • 5
  • 30
  • 55