Hi All,
I have 2 modules in ABP Suites: Master Data Module and Transaction Module . I have all the master data entity and its CRUD page created in Master Data Module. Now i want to create transaction entity, which its attribute requiring reference to the data entity in Master Data Module. i find out that the data entity created in Master Data Module cannot be found in Transaction Module as per the picture.Can you advise what to do?
This is the company entity created in Master Data Module.

This is the the page where i want to create data entity and its reference page in Transaction module. i cannot see company entity at all.

24 Answer(s)
-
0
- In ABP Suite, the “Entity” dropdown in Define a navigation property is populated by scanning the compiled assemblies of the currently selected module/solution. It does not automatically list entities that belong to a different module (like your “Master Data” module) unless that module is referenced and its assemblies are discoverable to Suite in the current solution context.
- ABP Suite only has an explicit checkbox for built-in ABP modules (Include entities from ABP modules)—it doesn’t have a similar “include entities from other custom modules” option in that dialog.
What to do (recommended, DDD-friendly approach):
- In the Transaction module, store only the FK as a value (e.g.,
CompanyId) and do not add an EF Core navigation to theCompanyaggregate from Master Data.- Example:
public class Transaction : AggregateRoot<Guid> { public Guid CompanyId { get; private set; } // Reference by Id only // ... }- For UI selection, use a lookup endpoint from the Master Data module (an application service returning
Id+ display fields) and consume it from the Transaction UI (Suite can generate lookups when the relationship is within the same module; for cross-module you typically wire the lookup manually).
If you still want a real navigation property (same DbContext scenario):
- Ensure Transaction solution/module references the Master Data module projects (Domain + EFCore as needed) so types are available at compile time.
- Build the solution successfully (Suite’s entity scanning requires a successful build).
- Then try defining the navigation again. If Suite still doesn’t list it, define the relationship manually in code (EF Core mapping + DTO/UI yourself). Suite’s navigation-property UI is primarily designed for entities inside the same module/solution plus built-in ABP modules.
Sources:
- https://abp.io/docs/latest/suite/generating-crud-page
- https://abp.io/community/articles/furp75ex
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Yes, i want real navigation property. Please tell me how to do so
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
- To create a real EF Core navigation property from an entity in your Transaction module to an entity in your Master Data module using ABP Suite, you must make ABP Suite see the Master Data module’s entity types. ABP Suite can do this by scanning extra module assemblies via
/.suite/module-entity-extension.json.
1) Make the Transaction solution depend on the Master Data module (compile-time)
In Visual Studio (or your IDE), add project references so the Transaction side can compile against Master Data types:
Transaction.Domain→ referenceMasterData.DomainTransaction.EntityFrameworkCore→ referenceMasterData.EntityFrameworkCore(and/orMasterData.Domainas needed)- Also ensure your Transaction module has the proper
[DependsOn(...)]module dependency on the Master Data module (Domain/EfCore module) so runtime registration is correct.
Then build the whole solution successfully.
2) Tell ABP Suite to include your custom module entities
In the root of the solution you open with ABP Suite, create/edit this file:
/.suite/module-entity-extension.jsonPut the Master Data domain assembly name there (the DLL name ABP Suite should scan):
{ "Modules": [ { "DomainProjectDllFileName": "MyCompany.MyProject.MasterData.Domain.dll" } ] }Notes:
- Use the exact DLL file name produced by the Master Data Domain project.
- After editing, rebuild the solution, then restart ABP Suite and reopen the solution.
3) Add the navigation in ABP Suite (Transaction entity)
Now go back to the Transaction entity → Navigation properties tab → Add navigation property. At this point, the Company entity from Master Data should appear in the Entity dropdown (because Suite can now scan that module’s domain DLL).
4) Generate and migrate
Click Save and generate, then:
- Add a migration in your DbMigrator / EF Core project
- Run DbMigrator to apply the FK and relationship changes.
Sources
- https://abp.io/docs/latest/suite/generating-crud-page (see “Extending with Custom Module Entities” /
module-entity-extension.json) - https://abp.io/docs/10.4/suite/generating-crud-page (same section, versioned)
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - To create a real EF Core navigation property from an entity in your Transaction module to an entity in your Master Data module using ABP Suite, you must make ABP Suite see the Master Data module’s entity types. ABP Suite can do this by scanning extra module assemblies via
-
0
Hi,
The Entity dropdown is empty because
Companylives in a different module (Master Data). By default Suite only lists entities from your Transaction solution itself, so entities from your other custom modules won't show up until you tell Suite to scan them.In your Transaction module solution:
Reference the Master Data module (its
*.Domainproject/package) and build the solution, so the Master Data Domain DLL ends up in the build output undersrc.Add a
.suite/module-entity-extension.jsonfile at the solution root:
{ "Modules": [ { "DomainProjectDllFileName": "YourCompany.MasterData.Domain.dll" } ] }- Open the navigation property dialog and check Include entities from ABP modules (Suite builds the solution first if it isn't already built). It'll scan that DLL and list
Companyin the Entity dropdown.
A note on what Suite generates here: on the transaction entity it adds a
CompanyIdforeign key rather than aCompanynavigation property on the aggregate itself, which follows ABP's guidance of referencing other aggregate roots by id. It still wires up a real EF Core relationship for that key (HasOne<Company>().WithMany().HasForeignKey(x => x.CompanyId)) and generates a separate...WithNavigationPropertiestype that joins to Master Data to show the company fields on the list/detail pages.Because that relationship is real, both entities have to live in the same database and the Transaction side's DbContext has to map
Company(i.e. the Transaction app references the Master Data module). So this fits a modular-monolith setup, not two independently deployed modules with separate databases.Docs: https://abp.io/docs/latest/suite/generating-crud-page (see the "Extending with Custom Module Entities" section).
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
thanks maliming :)
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
0
Hi,
The OK button is disabled because the dialog needs a Display property and there's none to pick for
Company. That's the property Suite uses as the visible text in the generated dropdown, and it's required — without it the button stays off.The catch is that Suite only offers string properties declared directly on the entity itself as the display property. Inherited ones (like the base
ConcurrencyStamp) don't count, which is whyCompanystill shows up in the entity list but the Display property field is empty. YourCompanyentity doesn't have its own string property, so there's nothing to select.To fix it, give
Companya string property (e.g.Name) in the Master Data module, rebuild that module so the DLL your Transaction solution references is up to date, then reopen the dialog. SelectCompanyagain, pick the display property, and OK will be enabled.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
0
Hi,
Thanks, that screenshot helps.
CompanyNameis there in the entity, so the source is fine.The thing is, this dialog doesn't read your entity source — it loads the compiled
WGBS_Connect.Domain.dlland reflects over it to build the Display property list. And Suite loads that DLL once per session and keeps it cached, so if it picked up an older build of the DLL (one from beforeCompanyNamewas added), it'll keep using that until Suite is restarted — which would leave the Display property empty and the OK button disabled, exactly like you're seeing.Could you try this:
- Rebuild the Master Data module and make sure the
WGBS_Connect.Domain.dllunder your Transaction solution'ssrcfolder is the fresh one that includesCompanyName(if you reference the module as a NuGet package, repack/reinstall it, not just rebuild the source). - Fully close ABP Suite and reopen it, then open the navigation property dialog again and select
Company.
If
CompanyNamestill doesn't show up as a display property after that, send me the compiledWGBS_Connect.Domain.dll(or a small repro project) at liming.ma@volosoft.com and I'll check it directly.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Rebuild the Master Data module and make sure the
-
0
Hi Maliming, Learn time both dll are of the same. I have email you^^
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Your email hasn't reached me yet — could you send it through https://wetransfer.com instead (to liming.ma@volosoft.com)? Attachments on the support thread and email sometimes get stripped.
To pin this down, the most useful thing would be the Transaction solution that reproduces it (a trimmed-down copy is fine). If you'd rather not share the whole thing, these two are enough:
- The compiled
WGBS_Connect.Domain.dll— the exact copy under your Transaction solution'ssrcfolder, since that's the one the dialog loads. - The
Companyentity source file(s), including any base or partial class if Suite split it (e.g.Company.csplus a...Base.cs).
With those I can load the same DLL and see exactly why
CompanyNameisn't offered as a display property.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - The compiled
-
0
Hi Maliming, I have just resend the email to you with the the links to download dll file from we transfer. Can you try?
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks for sending the DLL — that made it clear, and this is a bug on our side in ABP Suite.
When you reference an entity from another module, the Basic tab builds the Display property list only from properties declared directly on the entity class. Suite generated your entity's properties on the
CompanyBaseclass (your concreteCompanyinherits from it), so that list comes back empty, the Display property dropdown doesn't render, and the OK button never enables.You can get past this right now without changing the entity:
- Select
Company. - Switch to the Advanced tab.
- In the Display property field there, type
CompanyName(it's a free-text input, so it doesn't depend on that scan). - Click OK.
That fills in the display property, the rest of the fields are already set, and the generated lookup will use the real
CompanyNamecolumn — no extra property or database change needed.We'll fix the Basic tab scan so it also picks up properties from the generated
...Baseclass.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Select
-
0
Hi,
Since this turned out to be a bug on our side, I've refunded your ticket. The Advanced-tab step above will unblock you for now, and the Suite fix is on the way for an upcoming release.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
0
Hi,
This is by design. When "Include entities from ABP modules" is enabled, Suite's module-entity picker only offers aggregate roots as navigation targets — child entities aren't listed by that picker, which is why
Departmentdoesn't show up while it's modeled as a child.It comes down to how
Departmentis modeled:- If it's genuinely an independent concept in your domain (its own lifecycle and consistency boundary), make it an aggregate root. If it already uses a
Guidkey, useAggregateRoot<Guid>,AuditedAggregateRoot<Guid>, orFullAuditedAggregateRoot<Guid>, and give it a public string property likeNamefor the display field — then rebuild the module and restart Suite before selecting it again. (The picker reads module entity keys asGuid, so don't switch a non-Guiddomain key just to make it appear.) - If it's really a child of another aggregate, keep it that way and work with it through its owning aggregate root (or that module's application services), instead of selecting it as a direct navigation target.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - If it's genuinely an independent concept in your domain (its own lifecycle and consistency boundary), make it an aggregate root. If it already uses a
-
0
HI Maliming, Can explain more in details how to do for 2nd options?
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Quick note first: option 2 doesn't get
Departmentinto Suite's cross-module picker — that picker only lists aggregate roots. So option 2 is about how you wire it up, and the right wiring depends mostly on one thing: does a transaction need to save the selected department, or only show/pick departments?- If a transaction stores the chosen department (a
DepartmentIdon the transaction record), thenDepartmentis being referenced as an entity in its own right. In ABP that's the sign it should be modeled as an aggregate root rather than a child — decide it from the domain (does it have its own lifecycle and consistency boundary?), not just to get it into the picker. Once it's an aggregate root, Suite generates the reference the same way it did forCompany, and it can still keep its owner id (e.g.CompanyId) to record which master it belongs to. - If departments are only shown/selected under a chosen master and never stored on the transaction, keep
Departmentas a child. Load the list through the Master Data module — Suite already generates a service that returns a child's records by its master's id — and don't create a direct navigation to the child from the Transaction side.
One thing that affects the answer either way: cross-module references stay clean when the Master Data module exposes what others need through its own service/contract, rather than the Transaction module reaching directly into
Department's tables — this matters especially if the two modules might run as separate apps or databases.So I can give you concrete steps, could you tell me:
- Which entity owns
Department(which master is it a child of)? - Does a transaction need to save the selected department, or only display/pick it?
- Are both modules in one app sharing the same database, or separate services/databases — and is the UI MVC, Angular, or Blazor?
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - If a transaction stores the chosen department (a
-
0
Hi maliming, My reply as below.
- Company( Master entity) owns department (Child entity).
- Transaction need to save department because it is raised by company and department.
- Both modules using the same database and under same application. We are using blazor
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks — that settles it. Since a transaction has to save the department (raised per company + department), the department is referenced on its own from another module, so it should be an aggregate root rather than a child of
Company. Child entities are meant to be reached only through their aggregate root, so referencing one directly from another module is what you want to avoid.A few practical points for the change:
- Suite locks the entity type once an entity is saved, so you can't flip the existing
Departmentfrom Child to Master in the UI. You'll recreate it as a Master entity with an aggregate-root base class (AggregateRoot<Guid>,AuditedAggregateRoot<Guid>, orFullAuditedAggregateRoot<Guid>), remove the inline department management from theCompanypage, and check the generated migration so you don't drop existingDepartmentdata. - On the new
Department, addCompanyas a navigation property (this generates theCompanyIdand the relationship) and give it a string property likeName— the cross-module picker needs a string for the display field. It'll then show up for the transaction just likeCompanydoes; the module dependency and.suite/module-entity-extension.jsonyou set up forCompanyalready cover it. - A child uses cascade delete, but a reference between two aggregate roots does not — so decide what should happen to a
Departmentwhen itsCompanyis deleted. - On the transaction, if you keep both
CompanyIdandDepartmentId, validate on the server side (in the app service / domain, not only in the Blazor UI) that the department belongs to the company — the generated code only null-checks the ids. If the transaction doesn't need the company on its own, storing justDepartmentIdavoids the duplicate state.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Suite locks the entity type once an entity is saved, so you can't flip the existing
-
0
Hi Maliming, I guess i do not get the scenario clear enough. Let me explain again.
1.In our master data design, we have company(master entity) owns department(child entity). With this approach, we could enjoy the crud page design of ABP Suites as per below. They are created under Master Data module
Tested that we could not have set department as root entity once it is child entity

2.We created request table under transaction module using ABP Suites. We learn that we are not able to add department as attribute to the transaction table which is why we raise help ^^
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks, that makes it clear. The key point: Suite's standard cross-module selector only offers aggregate roots. As long as
Departmentstays a child ofCompany, the request won't get a Suite-generated reference to it through that selector — that part has to be wired by hand. So it comes down to keeping the master-detail (and wiring this one reference yourself) or makingDepartmenta first-class entity.Keeping the master-detail (recommended for your case):
You can keep
Departmentas a child and still let a request pick one. A clean shape:- On the request, reference
Companythe normal Suite way (you get the company picker and a real FK), and add a plainDepartmentId(Guid) property for the chosen department. - Load the department options filtered by the selected company (a dependent dropdown). Master Data already generates a paged "list by company id" service for the child — note it's paged with no search filter, so either page through it, or add a small dedicated lookup endpoint in Master Data if you want search/typeahead. A dedicated lookup also lets you give it its own permission, instead of requiring the full
DepartmentsCRUD permission just to create a request. - Validate on the server side (in the request's create/update) that the department belongs to the company — do that lookup/validation through Master Data's
Application.Contracts(add the module/package reference), not by touching its repository or DbContext. - Put this custom picker/validation code in the
*.Extended.cs/ customizable-code files so re-generating the entity doesn't overwrite it.
Things to keep in mind on this path:
- Suite doesn't generate a database foreign key for a plain
DepartmentIdproperty (only a navigation property does). If you want DB-level enforcement you'd add the FK yourself via a migration. - Deletion: the
Company → Departmentmapping uses cascade, but that's for physical deletes — audited entities soft-delete by default, so a deleted department is just hidden by the data filter, and an existing request'sDepartmentIdwould then resolve to nothing. Decide how to handle it (e.g. block deleting a department that's in use, or store the department name on the request for historical display).
Technically that
DepartmentIdpoints at an entity living inside theCompanyaggregate, so it's a pragmatic reference rather than a standard aggregate-root reference — Master Data stays responsible for validating and resolving it.Alternative — make
Departmentan aggregate root:Then the request references it the normal Suite way (auto-generated picker and relationship). You'd keep the "manage departments under a company" experience with a custom grid filtered by
CompanyIdon theCompanypage — that's custom UI, not Suite's master-detail feature. More setup up front, but cleaner ifDepartmentends up referenced from more places than just requests.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - On the request, reference
-
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
0
Hi,
These build errors are a separate topic from this cross-module question, so it's better to open a new question for them — we'll dig into it properly there.
A quick pointer in the meantime:
Lis the localizer, and in a Blazor module it comes from the module's component base (something likeOperationRequestComponentBase, which inheritsAbpComponentBaseand sets theLocalizationResource). Suite's generated pages@inheritsthat base to getL. A freshly created module has it and compiles fine, so thoseCS0103: 'L'errors point to that base being missing or not matching in yourOperationRequest.Blazorproject.When you open the new question, please include:
- Whether
OperationRequest.Blazorhas a...ComponentBaseclass that inheritsAbpComponentBase— its class name and namespace. - The
@inherits ...line from one of the failing generated.razorfiles. - The
_Imports.razorof that project.
With those we can pinpoint why
Lisn't resolving.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Whether





