Hello, I have an area in my program which repeats itself in different places again and again. I would like to implement this as a view component. A database table is always retrieved in this view component. This database table always has the structure ID, "name". Depending on the area where the view component is used, a different database table is required. The table name of the view component is therefore passed as a parameter. What is the best way to implement this in the existing abp structure, since you normally always work with a particular (named) repository using dependency injection. In my case I would need a "generic" repository, which is filled by the required database table (parameter table name). Even custom repositories always seem to depend on a specific entity. I hope this is understandable :-)
Hi ismcagdas, I think my problem was the fulltextsearch in database. The magic words are "changes might not be reflected immediately in the full-text index.". So database was updated but when "dataTable.ajax.reload();" was executed the fulltextindex was not refreshed. Thanks for your time.
Hi ismcagdas, thanks for reply. Searchtext is used for test purposes and the value "Spieth" is written "hard" into database. It's read from modal form text field and is not changed. In real application searchtext should be written by a stored procedure. The only special thing about the Searchtext column in the database is that it is a full text indexed column.
var dataTable = _$addressSearchTable.DataTable({
paging: true,
serverSide: true,
processing: true,
listAction: {
ajaxFunction: _addressService.getAddressPersonCompaniesForDatatable,
inputFilter: function () {
return {
filter: $('#FilterAddressText').val()//,
//permissions: _selectedPermissionNames,
//role: $("#RoleSelectionCombo").val(),
//onlyLockedUsers: $("#UsersTable_OnlyLockedUsers").is(':checked')
};
}
},
Because of a test with a breakpoint I'm writting about a time problem. When I place a breakpoint at the end of "CreateOrUpdateAddress" nothing is written in database. After one step more (F10) out of the function debugger stops at function "public class AppnameEntityFrameworkCoreModule : AbpModule" at line "Configuration.Modules.AbpEfCore().AddDbContext<AppnameDbContext>(options =>" and data is written in database. After that done-function and dataTable.ajax.reload() is called. In this case the new address is displayed in the datatable as expected.
But when I run the insert dialog without breakpoint, the new address isn't shown in the datatable. Only after a refresh.
Similar behavior with update dialog. I can see because of the updated data in the datatable, that address and name data is written in database, but the updated searchtext is written to late, so that for example changed name from "Spieth" to "Test", search still finds the row with searchtext "Spieth" and not the updated row with "Test".
Hello, I have three database tables Address, PersonCompany and a link table AddressPersonCompany (m:n). In the frontend there is a display form which is very similar to the page "users" - a text field for a search word and a datatable to display the search result (addresses).
Following the instructions "Using-Stored-Procedures,-User-Defined-Functions-and-Views" I created three custom repositories.
If a new address is created via the modal window, first the Address table, then the PersonCompany table and finally the link table AddressPersonCompany is filled. In AddressPersonCompany there is an additional column in which a search text is written. For test purposes, the search text is predefined as "Spieth".
The problem is that before the insert the search was restricted to "S", for example. Accordingly the new dataset should appear immediately in the datatable, because it also starts with "S". After the insert, as with "Users" a
function getAddresses() {
dataTable.ajax.reload();
}
triggered. However, the new data record is only displayed after a page update (for example, F5).
When the record is updated, you can see that the Address and PersonCompany table is written on time, but the search text is changed too late. In the Datatable the changed values already exist, but the dataset should not be displayed anymore, because the search text was changed from "Spieth" to e.g. "Test".
Therefore I think that the function "getAddresses()" is executed before the dataset has been updated or completely inserted.
Can you give me a hint how to solve the problem?
Here is my insert function
public async Task CreateOrUpdateAddress(CreateOrUpdateAddressInput input)
{
if (input.AddressPersonCompanyId.HasValue)
{
// Update addressPersonCompany
await UpdateAddressAsync(input);
}
else
{
// Insert addressPersonCompany
await InsertAddressAsync(input);
}
// Save changes to database
//await CurrentUnitOfWork.SaveChangesAsync();
}
protected virtual async Task InsertAddressAsync(CreateOrUpdateAddressInput input)
{
var addressPersonCompany = ObjectMapper.Map<AdrAddressPersonCompany>(input);
addressPersonCompany.AddressId = await _addressRepository.InsertAndGetIdAsync(addressPersonCompany.Address);
addressPersonCompany.PersonCompanyId = await _personCompanyRepository.InsertAndGetIdAsync(addressPersonCompany.PersonCompany);
addressPersonCompany.Searchtext = "Spieth";
await CurrentUnitOfWork.SaveChangesAsync(); //To get new user's Id.
//AdrAddressPersonCompany _newAdrAddressPersonCompany = await _addressPersonCompanyRepository.InsertAsync(addressPersonCompany);
var addressPersonCompanyId = await _addressPersonCompanyRepository.InsertAndGetIdAsync(addressPersonCompany);
await CurrentUnitOfWork.SaveChangesAsync(); //To get new user's Id.
// Create searchtext in table adrAddressPersonCompanies
//await _addressPersonCompanyRepository.UpdateSearchtextOnAddressPersonCompanies(addressPersonCompany.AddressId, addressPersonCompany.PersonCompanyId, _session.TenantId);
}
protected virtual async Task UpdateAddressAsync(CreateOrUpdateAddressInput input)
{
//Update existing AddressPersonCompany
var address = await _addressRepository.GetAsync(input.AddressId);
address.Street = input.AddressStreet;
address.Location = input.AddressLocation;
address.HouseNumber = input.AddressHouseNumber;
address.Zipcode = input.AddressZipcode;
await _addressRepository.UpdateAsync(address);
var personCompany = await _personCompanyRepository.GetAsync(input.PersonCompanyId);
personCompany.NameCompany = input.PersonCompanyNameCompany;
personCompany.Firstname = input.PersonCompanyFirstname;
personCompany.TitleId = input.PersonCompanyTitleId;
personCompany.CompanyAddOn = input.PersonCompanyCompanyAddOn;
await _personCompanyRepository.UpdateAsync(personCompany);
await CurrentUnitOfWork.SaveChangesAsync(); //To get new user's Id.
// Create searchtext in table adrAddressPersonCompanies
await _addressPersonCompanyRepository.UpdateSearchtextOnAddressPersonCompanies(input.AddressId, input.PersonCompanyId, _session.TenantId);
}
and the standard part of _CreateOrEditModal
this.save = function () {
if (!_$form.valid()) {
return;
}
var address = _$form.serializeFormToObject();
_modalManager.setBusy(true);
// direkt die Funktion aus AddressAppService verwendet
_addressService.createOrUpdateAddress(address).done(function () {
abp.notify.info(app.localize('SavedSuccessfully'));
_modalManager.close();
abp.event.trigger('app.createOrEditAddressModalSaved');
//location.reload();
}).always(function () {
_modalManager.setBusy(false);
});
};
Can you give me a hint, where to do
addressPersonCompany.NormalizedSearchTarget = String
.Join(" ", e.PersonCompany.NameCompany, e.PersonCompany.Firstname, e.Address.Street, e.Address.Location)
.ToUpperInvariant();
Thanks for reply. Without including Abp.Linq.Expressions namespace, it is Abp.Collections.Extensions.WhereIf(). I will test your suggestion next week.
using Abp.Linq.Extensions;
public class AddressAppService : MyAppAppServiceBase, IAddressAppService
{
public AddressAppService(IRepository<AdrAddress> addressRepository,
IRepository<AdrPersonCompany> personCompanyRepository,
IRepository<AdrAddressPersonCompany> addressPersonCompanyRepository,
IRepository<AdrTitle> titleRepository,
IDbContextProvider<TreasureMapDbContext> dbContextProvider)
{
_addressRepository = addressRepository;
_personCompanyRepository = personCompanyRepository;
_addressPersonCompanyRepository = addressPersonCompanyRepository;
_titleRepository = titleRepository;
_dbContextProvider = dbContextProvider;
}
public ListResultDto<AddressPersonCompanyDto> GetAddressPersonCompanies(GetAddressesInput input)
{
var searchwords = !input.Filter.IsNullOrEmpty() ? input.Filter.Split(" ") : null;
var addressPersonCompanies = _addressPersonCompanyRepository
.GetAll()
.Include(adr => adr.Address)
.Include(pers => pers.PersonCompany)
.Include(tit => tit.PersonCompany.Title)
.WhereIf(
!input.Filter.IsNullOrEmpty(),
e => searchwords.All(w => String
.Join(" ", e.PersonCompany.NameCompany, e.PersonCompany.Firstname, e.Address.Street, e.Address.Location)
.Contains(w, StringComparison.InvariantCultureIgnoreCase))
)
.ToList();
return new ListResultDto<AddressPersonCompanyDto>(ObjectMapper.Map<List<AddressPersonCompanyDto>>(addressPersonCompanies));
}
}
Does that help you?
Hi maliming, you are right. But I think the problem also has something to do with the namespace Abp.Linq.Extensions. Running the query ....ToList() without using Abp.Linq.Extensions namespace works as expected. If I add the namespace, there is an error.
On the other side ...AsQueryable() doesn't work with or without the namespace Abp.Linq.Extensions.
I am trying to create a query that queries an address and person using multiple keywords. There is a person table, an address table and a link table addressPerson (m:n). The query looks like this:
var searchwords = !input.Filter.IsNullOrEmpty() ? input.Filter.Split(" ") : null;
var query = _addressPersonCompanyRepository
.GetAll()
.Include(a => a.Address)
.Include(p => p.PersonCompany)
.Include(t => t.PersonCompany.Title)
.WhereIf(
!input.Filter.IsNullOrEmpty(),
e => searchwords.All(w => String
.Join(" ", e.PersonCompany.NameCompany, e.PersonCompany.Firstname, e.Address.Street, e.Address.Location)
.Contains(w, StringComparison.InvariantCultureIgnoreCase))
)
//.ToList();
.AsQueryable();
var addressCount = await query.CountAsync();
var addressPersonCompanies = query
.OrderBy(input.Sorting)
//.PageBy(input)
.ToList();
var addressPersonCompanyListDto = ObjectMapper.Map<List<AddressPersonCompanyDto>>(addressPersonCompanies);
return new PagedResultDto<AddressPersonCompanyDto>(
addressCount,
addressPersonCompanyListDto
);
Without the namespace Abp.Linq.Extensions and .ToList() the query works if searchwords contains one or more strings. If the namespace is added because it is needed for .PageBy, I get the following error message:
System.InvalidOperationException HResult=0x80131509 Nachricht = The LINQ expression 'DbSet<AdrAddressPersonCompany> .Where(a => __ef_filter__p_0 || !(((ISoftDelete)a).IsDeleted) && __ef_filter__p_1 || (Nullable<int>)((IMustHaveTenant)a).TenantId == __ef_filter__CurrentTenantId_2) .Join( outer: DbSet<AdrPersonCompany> .Where(a0 => __ef_filter__p_3 || !(((ISoftDelete)a0).IsDeleted) && __ef_filter__p_4 || (Nullable<int>)((IMustHaveTenant)a0).TenantId == __ef_filter__CurrentTenantId_5), inner: a => EF.Property<Nullable<long>>(a, "PersonCompanyId"), outerKeySelector: a0 => EF.Property<Nullable<long>>(a0, "Id"), innerKeySelector: (o, i) => new TransparentIdentifier<AdrAddressPersonCompany, AdrPersonCompany>( Outer = o, Inner = i )) .Join( outer: DbSet<AdrAddress> .Where(a1 => __ef_filter__p_6 || !(((ISoftDelete)a1).IsDeleted) && __ef_filter__p_7 || (Nullable<int>)((IMustHaveTenant)a1).TenantId == __ef_filter__CurrentTenantId_8), inner: a => EF.Property<Nullable<long>>(a.Outer, "AddressId"), outerKeySelector: a1 => EF.Property<Nullable<long>>(a1, "Id"), innerKeySelector: (o, i) => new TransparentIdentifier<TransparentIdentifier<AdrAddressPersonCompany, AdrPersonCompany>, AdrAddress>( Outer = o, Inner = i )) .Where(a => __searchwords_0 .All(w => string.Join( separator: " ", value: new string[] { a.Outer.Inner.NameCompany, a.Outer.Inner.Firstname, a.Inner.Street, a.Inner.Location }).Contains( value: w, comparisonType: InvariantCultureIgnoreCase)))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information. Quelle = Microsoft.EntityFrameworkCore
I have tested:
Is there any workaround or a better way to get results from database with multiple keywords over multiple columns? I'm using .netCore & JQuery