FWIW - I've sometimes had to go the logs in AppData to get the stack dump.
HTH
I'm not ANZ support - but I've found the best way is through abstraction and domain services.
For example - You could create a business logic class that does what you need. Entity relational logic, business rules, etc., and call that from the standard classes.
You may want to create more than one.
Then, in the scaffolded / default classes - you call your classes instead.
When you regen an entity or upgrade, you'll want to look at your changes - and carry over your changes.
In effect - based on advice I've gotten for a similar question - this was the advice I got.
As a simple example - in an app services createoredit method..You would copy createoredit, create, and edit to your class, and modify there, then, in the app service, inject your class and use the default methods to just wrap yours.
If you regen the entity, it will overwrite this, so you'll have to update the appservice methods to use yours instead.
It can be tedious, but I've found Checkin -> Scaffold / merge -> examine diff of all changed files and fix until it builds -> checkin to be a workable workflow.
I've actually suggested on GitHub that they leverage regions to carry over custom code.
One of my practices as well, is I use a custom region at the end of any file I know will be overwritten by the RAD tool. It makes carrying my changes over much easier, as I copy the start of that region to the end of the file to the end of the new file.
You can modify methods outright doing that if you want, then simply comment out the updated methods.
In the end, though - the advice to do a domain service has been my go to approach.
Of note - when creating domain services, where you put them matters; especially if you want to get to the DbContext. The documentation guides you to put them in Core, but I've begun to put more and more of them in the Application project.
The first project I did with ANZ, several years ago - I had a completely separate project in the solution - but I wouldn't recommend that approach now.
My only other bit of advice is not to move the files it generates. When you run the RAD tool, it'll simply recreate the file where it was, and if you've moved it, the build will fail and you'll have to unravel the issues.
One thing I really don't like about the project structure is how it dumps DTOs into one folder, instead of breaking them out for the appservice they're used by. They could all be in the same namespace, but grouping them by app service would be useful. Alas, that is unecessary.
I found this MS article - I will attempt to use this information to accomplish what I need to do.
hey dmux - have you looked at DeleteAllUserNotifications in NotificationAppService?
It hits the notification manager, which hits the notifcationstore, which has transient dependency. (all within ABP project).
IRepository<NotificationInfo, Guid> _notificationRepository;
namespace Abp.Domain.Repositories.
You can inject that into your job - maybe get you want you need.
In ABP project, check the NotificationStore in Abp.Zero.Common.
Yes, that's what I'm trying to figure out how to do.
Microsoft docs say:
Join<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,TInner,TResult>)
I found this example on Stack Overflow which looks promising: https://stackoverflow.com/questions/19644617/linq-multiple-join-iqueryable-modify-result-selector-expression
here's what I am doing for now:
var uId = AbpSession.UserId;
var depList = (from ed in _employeeDepartmentRepository.GetAll()
join du in _departmentUserRepository.GetAll() on ed.DepartmentId equals du.DepartmentId
where du.UserId == uId
select ed.EmployeeId).ToList();
var query = _lookup_employeeRepository.GetAll()
.WhereIf(
!string.IsNullOrWhiteSpace(input.Filter), e =>
e.firstName.Contains(input.Filter) || e.lastName.Contains(input.Filter)
)
.Where(e => depList.Contains(e.Id));
Not the most elegant, and it hits the database twice.
Ultimately, I may have to avoid using WhereIf and just test if there's a filter and create one or two queries.
Something like:
If input.filter then Query with a filter else Query without a filter
8.9/ jQuery
If I have repositories I wish to join, and still leverage WhereIf for filtering, what's the ANZ way?
For example:
Suppose we have this:
var query = _lookup_employeeRepository.GetAll().WhereIf(
!string.IsNullOrWhiteSpace(input.Filter),
e=> e.email != null && e.email.Contains(input.Filter)
);
And what I want to do is something like this:
var query = from e in _lookup_employeeRepository.GetAll()
join ed in _employeeDepartmentRepository.GetAll() on e.Id equals ed.EmployeeId
join du in _departmentUserRepository.GetAll() on ed.DepartmentId equals du.DepartmentId
where e.TenantId == tId && du.UserId == uId && (e.firstName.Contains(input.Filter) || e.lastName.Contains(input.Filter))
select e;
However - instead of doing it that way, use the WhereIf for filtering..
So I reviewed this: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.join?view=netcore-3.1
So I'd like to use Whereif, so my query would look something like:
var query2 = _lookup_employeeRepository.GetAll()
.Join(_employeeDepartmentRepository.GetAll(), Id => EmployeeId, ) // <----- How do I do this?
.WhereIf(
!string.IsNullOrWhiteSpace(input.Filter), e =>
e.firstName.Contains(input.Filter) || e.lastName.Contains(input.Filter)
);
Do I have to take the tables .toList() first? If so, I'll do it as per my second example in this (using from e in ...)
So, the reason one might want to use HandFire over the built in background jobs is granularity of control?
What's the reason to use hangfire?
It seems very robust, but I'm not grasping why one would want to use hangfaire over the existing job engine in ABP.
One benefit I see is that it's database driven, so could be run on a different server than the web server - but it seems the existing job engine could be used in the same manner.
I'm just trying to understand what the rationale is to use handfire.
Does it benefit web app performance in some way, because of its threading?
Quick update - I've think I've addressed this by using .ToString("s") for these fields.
It appears moment's parsing is to blame.
I'll let you know.
I'm having to do this to avoid that happening. Is the the correct way?
var data = this.dataTable.data().toArray();
this.dataTable.clear();
this.dataTable.draw();
for (var i = 0; i < departmentList.length; i++) {
data.push(departmentList[i]);
}
for (var i = 0; i < data.length; i++) {
this.dataTable.row.add(data[i]);
}
this.dataTable.draw();
This seems counterintuitive.