- ABP Framework version: v4.3.0
- UI type: Angular
- DB provider: EF Core / MongoDB
- Tiered (MVC) or Identity Server Separated (Angular): no
- Exception message and stack trace: N/A
- Steps to reproduce the issue:"
I've got an entity with a backing field navigation property like so.
public class Customer : FullAuditedAggregateRoot<Guid>, IHasTimelineTopic, IHasAttachments
{
private readonly HashSet<Contact> _contacts = new();
public IEnumerable<Contact> Contacts => _contacts?.ToList();
public void AddContacts(IEnumerable<Contact> contacts)
{
Check.NotNull(contacts, nameof(contacts));
foreach (var contact in contacts)
{
_contacts.Add(contact);
}
}
public void RemoveContacts(IEnumerable<Contact> contacts)
{
Check.NotNull(contacts, nameof(contacts));
foreach (var contact in contacts)
{
_contacts.Remove(contact);
}
}
}
it's EF config looks like
builder.Entity<Customer>(b =>
{
b.ToTable(FooConsts.DbTablePrefix + "Customers", FooConsts.DbSchema);
b.ConfigureByConvention();
b.HasMany(x => x.Contacts).WithMany(x => x.Customers)
.UsingEntity(join => join.ToTable("AppCustomerContacts"));
b.Navigation(nameof(Customer.Contacts))
.UsePropertyAccessMode(PropertyAccessMode.Field);
});
In my AppService I can update it like so
[Authorize(FooPermissions.Customers.Edit)]
public virtual async Task<CustomerDto> UpdateAsync(Guid id, CustomerUpdateDto input)
{
var customer = await _customerRepository.GetAsync(id);
ObjectMapper.Map(input, customer);
var contacts = await _contactRepository.FindListAsync(input.ContactIds);
customer.AddContacts(contacts);
var toRemove = customer.Contacts.Where(x => input.ContactIds.Contains(x.Id) == false).ToList();
customer.RemoveContacts(toRemove);
customer = await _customerRepository.UpdateAsync(customer, autoSave: true);
return ObjectMapper.Map<Customer, CustomerDto>(customer);
}
this works fine and generates two SQL statements, one to update the AppCustomerContacts xref table and one to update the entity itself.
I'm trying to write a console aplication to load some data from an Excel file. I followed the strucure of the included DbMigratior app and I've got :
- Program.cs which configures the Logger and creates the HstBuilder, registering a hosted service...
- DataSeederHostedService whichis an
IHostedServiceand takes anIHostApplicationLifetimeas a constructor parameter. It has aStartAsync()method which does just like the DbMigratior. It creates aDataSeederModulefrom theAbpApplicationfactory, callsUseAutoFac()andAddLogging(). Initializes the application, gets aDataSeedingServicefrom theServiceProviderand calls mySeedAsync()method. - My
DataSeedingServiceis anIDomainServicewhich takes a few repositories, theIGuidGeneratorandIUnitOfWorkas constructor paramerters.
The DataSeedingService adds Contacts to my Customers in the same way as above, using .AddContacts() but when I call await _customerRepository.UpdateAsync(customer, true); it only generates a single SQL statement to update the entity and doesn't insert anything into AppCustomerContacts.
What am I missing?
Here's how SeedAsync() calls the
contact = await _contactRepository.InsertAsync(contact, true);
customer = await _customerRepository.GetAsync(customerId);
customer.AddContact(contact);
_logger.LogInformation($"\t Adding contact to customer {customer.Name}");
customer = await _customerRepository.UpdateAsync(customer, true);
My DataSeederModule looks like this
[DependsOn(
typeof(AbpAutofacModule),
typeofFooDomainModule),
typeof(EFooEntityFrameworkCoreModule),
typeof(FooApplicationContractsModule)
)]
public class FooDataSeederModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBackgroundJobOptions>(options =>
{
options.IsJobExecutionEnabled = false;
});
}
}
Why isn't my console app generating two SQL statements? What am I missing? Do I need to reference another module or configure something at app startup?
4 Answer(s)
-
0
Hi,
May be you need add the
[UnitOfWork]to theSeedAsyncmethod[UnitOfWork] public virtual async Task SeedAsync() { ...... contact = await _contactRepository.InsertAsync(contact, true); customer = await _customerRepository.GetAsync(customerId); customer.AddContact(contact); _logger.LogInformation($"\t Adding contact to customer {customer.Name}"); customer = await _customerRepository.UpdateAsync(customer, true); } -
0
Hi @liangshiwei. I've added that and it still only generates the update statement for the Customer.
Anything else I can try?
-
0
Hi,
Can you provide a project to reproduce? shiwei.liang@volosoft.com thanks.
-
0
This question has been automatically marked as stale because it has not had recent activity.