Ok - the Rad tool only does one-to-one.
Examining the MS documents - I see I can add, for example List<Department> Departments to my Employee entity.
However, I think this will break migrations.
Thus, I'm looking at the User and Roles - it seems the netZero / ABP way is to:
On the GetUserForEditOutput class has an Array of UserRoleDto.
When GetUserForEdit is call - it goes to the RoleManager which gets all roles, then it selects those into a UserRoleDto.
Then it adds that to the GetUserForEditOutput class and returns it.
On Update or Save - it uses CreateOrUpdateUserInput, which has role names as an array of Strings[].
On update, it sets the roles via the UserManager, which leans on the RoleManager - and it does all this by the role name.
Internally, this takes this array string, finds each role by normalized name, finds the role, then deletes it from UserRoleDto by the Role.Id, or adds it to the UserRoleDto table.
In the modal create or edit js - on save, it goes through the list of checked roles, and builds a string by name, assigns the model, and that's posted back.
This list are the checkboxes under the wrapper div of class user-role-checkbox-list.
The view model is CreateOrEditUserModalViewModel, which is inheriting from GetUserForEditOutput, which has the UserRoleDto array (as mentioned above.
The User inherits from AbpUser which is based on AbpUserBase, which has ICollection<UserRole> Roles.
For mapping, in the customDtoMapper - there's configuration.CreateMap<Role, OrganizationUnitRoleListDto>(); Under the User object, which seems to have more to do the OUs than the actual Roles' ICollection<UserRole>.
The object mapper does not handle roles, instead it leans on the UserManager. It goes through each role, and calls IsInRoleAsync from the userManager, which then goes to our UserRole table and queries it, returning a bool if the list of roles the user has contains the passed name.
It does this each time (inefficient, IMHO, but irrelevant).
So, based on this - to accomplish what I would need to do the following:
I create an Entity for Employee Department membership I modify the DTOs for my employee to have an Arrays / Lists for the EmployeeDepartment entity. Then, in my Employee App Service, I populate the EmployeeDepartment list / array on the Employee DTOs. In the view model, I add this array of EmployeeEntityDTOs, rendering it however I wish (perhaps a modal). Then, on post back, when saving the employee, I also have to update my EmployeeDepartment entity, adding new entries and removing the old ones.
So, in summary, my requirements are:
Am I missing anything?
I don't know if it helps - I run into this sometimes, especially if I change from modal to no-modal.
When this happens, I let it fail, then manually build, check my error list, and clean up issues.
Then I run it again.
Rinse repeat until it completes.
Sometimes I have custom code referencing a property I'm changing, or something like that.
Right now my process is checkin (or branch) Do the above until migration is happy. Then I move all custom code over. Commit (or merge)
8.9, jquery.
Scenario: An employee can belong to multiple departments. Using the Power Tool, I can pick a FK relationship, but it's only one to one.
Per this post: https://support.aspnetzero.com/QA/Questions/6933/How-to-generate-relational-entities-using-abp-Power-tool One to Many is supported.
How do we do this?
If this is no longer the case? How do we accomplish this in the asp.net zero / aspboilerplate way?
Of note - my local time zone is CST, which is -6 hours offset from UTC, yet it's showing 6 AM. We're in Daylight savings, so currently it's -5 hours.
If it were somehow parsing incorrectly, and getting midnight UTC, you'd think it'd get 7PM or 6PM.
I'll test this further and see where 6:00 AM is coming from.
I did - It is correct, both the IANA and TimeZoneInfo.
Like I said, If I change the formatting to include the date along with it, it shows the correct time (format: 'L LT').
But if I use only LT, the value is incorrect. It's 6:00 AM regardless of what the value in the input field is (I should clarrify - regardless of the input value. I haven't tested this by changing my local timezone.)
In the cshtml, if I formatted the datetime to "t" (putting only the time in the input value) it would show the correct time.
Right now - I'm having to set that value via the above; which is fine - but not expected.
For what it's worth - here's how I'm having to address it:
$('.date-picker').each(function (i, e) {
$(e).val(moment($(e)[0].defaultValue).format("HH:mm A"));
})
Is this the normal way it's handled?
I have an input with a DateTime.
Looking at raw source, what comes down is correct
6/23/2020 9:00:00 AM
In the createoredit.js, there is:
$('.date-picker').datetimepicker({
locale: abp.localization.currentLanguage.name,
format: 'L'
});
by default.
If I set format to 'L LT' is displays correctly.
If I set format to LT, it changes the time to "6:00 AM".
The only way I can get the correct time to show is to format my DateTime with .ToString("t")
Is this something I'm doing wrong?
Thanks for any advice.
-> 8.9, Jquery
When the RAD tool scaffolds an entity with a boolean property, that uses filtering, it generates WHEREIF statements such as
.WhereIf(input.HasScheduleFilter > -1, e => (input.HasScheduleFilter == 1 && e.HasSchedule) || (input.HasScheduleFilter == 0 && !e.HasSchedule))
What I'm seeing is the input object's int property is 0 by default, resulting in it always being filtered.
Is anyone else experiencing this, or am I doing something wrong.
If I'm doing it correctly, then my solution has been to set a default value for boolean properties in the GetAll<entity>Input class, such as:
public int HasScheduleFilter { get; set; } = -1;
For scaffolding purposes, I'd suggest setting that default value for boolean properties (which are ints in the input class it creats) in the GetAllForLookupTableInput template files for RAD tool, if you're going to use this logic for the WhereIf, to avoid having to explicitly set this to -1 when doing something like:
var Object = await _<entity>AppService.GetAll(new GetAll<entity>Input()
{
HasScheduleFilter = -1,
});
2nd question - does my setting these default values to -1 raise any potential issues I'm not aware of?
if using OUs and entities. it's straightforward to get an entity and it's children based on the examples. ( adding keyword for searching Orginazational Units )
How might one leverage this to find the "deepest" value in the tree for a specific child?
For example, if my entities have a nullable property called manager. Lets assume the root entity has a value of Bob.
4 layers deep an entity has the manager property set to a different value, Sharon.
finally, below that, there is an entity for employee, Mike.
How might one find out who Mike's immediate manager is?
if i start with Mike and recusively examine parents upward until i get a value, this can be done.
But if i have 1000s of employees?
is the only solution to do this recursive upward query, or is there a best practice when getting children to get the "deepest" manager to the child?
Can the OU code be leveraged somehow to get the employee element with the manager value of Sharon without recursivly crawling up the OU parents for enery child untill i get a value, each time?
i see this as highly inefficient and would hurt performance.