Generic "Create" method in .NET Core that creates two entities

34 Views Asked by At

I have two .NET Core entities; UserAccount and Customer that has UserAccountId as foreign key. I want to have a one generic method that first creates UserAccount. Then I take UserAccountId from it and then save it in Customer entity. All in one request. Also I have generic Create method. All this would be trivial to me if it weren't for these generics and inheriting everywhere I go: Controllers, Services, overriding... so this is a setup:

Generic BaseCRUDService: (T is for Models, TDb is for DatabaseModels, TCreate is for Request model I'm sending through controllers)

    public class BaseCRUDService<T, TDb, TSearch, TCreate, TUpdate> 
    : BaseService<T, TDb, TSearch> 
    where TDb : class where T : class 
    where TSearch : BaseSearchObject
{
    public BaseCRUDService(DataDbContext context, IMapper mapper)
       : base(context, mapper)
    {}

    public virtual async Task PrepareBeforeCreate(TDb db, TCreate create)
    {}

    public virtual async Task<T> Create(TCreate create)
    {
        var set = context.Set<TDb>();

        var entity = mapper.Map<TDb>(create);

        set.Add(entity);

        await PrepareBeforeCreate(entity, create);

        await context.SaveChangesAsync();

        return mapper.Map<T>(entity);
    }
}

This is an implemenation of UserAccountService:

public class UserAccountService 
    : BaseCRUDService<Models.UserAccount, Database.UserAccount, UserAccountSearchObject, UserAccountCreateRequest, UserAccountUpdateRequest>, IUserAccountService
{

    public UserAccountService(DataDbContext context, IMapper mapper) 
        : base(context, mapper)
    {}

    public override async Task PrepareBeforeCreate(Database.UserAccount entity, UserAccountCreateRequest create)
    {
        entity.PasswordSalt = GenerateSalt();
        entity.PasswordHash = GenerateHash(entity.PasswordSalt, create.Password);
    }
}

When I hit CustomerService Create method (which by the way is the same as UserAccountService, inherits BaseCRUDService also and uses the same Create method), I need to call Create Method that will first create UserAccount and then I'll set that UserAccountId to the Customer.

I tried calling userAcountService.Create(create) in CustomerService method PrepareBeforeCreate like this:

public override async Task PrepareBeforeCreate(Database.Customer entity, CustomerCreateRequest create)
    {
        var userAccountEntity = userAccountService.Create(create as UserAccountCreateRequest);
        entity.UserAccountId = userAccountEntity.Id;
    }

but what I eventually get and I kinda get it is this error:

A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext.

So, my question is basically this: is there anyway I could modify this generic method or add to it to insert two models on one request? Thanks.

0

There are 0 best solutions below