- 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
IHostedService
and takes anIHostApplicationLifetime
as a constructor parameter. It has aStartAsync()
method which does just like the DbMigratior. It creates aDataSeederModule
from theAbpApplicationfactory
, callsUseAutoFac()
andAddLogging()
. Initializes the application, gets aDataSeedingService
from theServiceProvider
and calls mySeedAsync()
method. - My
DataSeedingService
is anIDomainService
which takes a few repositories, theIGuidGenerator
andIUnitOfWork
as 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 theSeedAsync
method[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.