How to do eager loading in nopcommerce 4.50

7 месяцев назад
Hi All.   How to do an eager loading in nopcommerce 4.50? Attempting to load a Vendor when loading mySupplier in the following example results in Vendor being set to null. The mapping meant to be one-to-one using Id of both objects as the mapping key.


// MySupplierService
var mySupplier = await _mySupplierRepository.GetByIdAsync(mySupplierId);



using Nop.Core;
using Nop.Core.Domain.Vendors;

namespace Nop.Plugin.MyPlugin.Domain.MySupplier
{
    public class MySupplier : BaseEntity
    {
        //MySupplier properties
        .....      

        public virtual Vendor Vendor { get; set; }
    }
}


Thank you!
7 месяцев назад
I may have found an answer to my own question in https://docs.nopcommerce.com/en/developer/plugins/plugin-with-data-access.html

Something to remember is that we do not have navigation properties (relational properties), because the Linq2DB framework, which we use to work with databases does not support the navigation properties.


I have a different question then. What is the practice in nopcommerce for implementing inheritance using Table-per-type (TPT)  mapping strategy?
7 месяцев назад
Use services to get to the underlying child domain objects. For example:

var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
7 месяцев назад
New York wrote:
Use services to get to the underlying child domain objects. For example:

var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);


Thanks. This is my current work around, but I was hoping to better understand how to implement Table-per-type (TPT)  mapping strategy. It somehow worked in 4.40.x but does not seem to work in 4.50.x
7 месяцев назад
Well technically, I think nopC is still doing Table-per-type (TPT) in the sense that there is  table per entity, and certain properties are inherited.  For example, look at
    public partial class Product : BaseEntity, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported, IDiscountSupported<DiscountProductMapping>, ISoftDeletedEntity

Product is a table in the DB.  The BaseEntity, IAclSupported, and ISoftDeletedEntity provide additional properties (Table columns) not defined directly in Product class.

LINQ to DB is a different Object-Relational Mapping (ORM) framework than Entity Framework, and it has its own way of handling relationships between entities.  It doesn't have the concept of navigational properties in the same way that Entity Framework does.

In Entity Framework, navigational properties are used to represent relationships between entities and provide a convenient way to navigate and work with related data.

In LINQ to DB, you typically work with relationships using JOIN operations in LINQ queries. You explicitly join tables and select the related data you need. LINQ to DB doesn't generate navigational properties for you automatically.

However, in nopCommerce plugins, you're more likely working within the context of the 'parameters' you receive in the methods of the interfaces you are supporting (either directly or overridden, etc.).  Therefore, you would have one or more entities (e.g. an Order, ShippingOptionRequest, PaymentOptionRequest, etc.), so you're not likely going to "work with relationships using JOIN operations in LINQ queries".  You would just call the service methods (e.g., GetCustomerByIdAsync) to get the child objects.   So, it's now not considered a "work around"; rather it is "by design" ;)    And to address your topic title, you can consider that the "eager loading" is somewhat addressed by the fact that nopC is caching the entities, so it's likely your service call won't need to be hitting the DB again.
7 месяцев назад
This is not quire what I was referring to. Here is a bit more context based on the project that I'm upgrading: The project has a class MySupplier which extends Vendor with it's own set of properties.   (MySupplier : Vendor)

In NopCommerce 4.40.4 (which is used on the current working version of the site) the attributes of MySupplier and Vendor are stored in their respective tables in the DB (MySupplier Table and Vendor Table) and referenced  by a foreign key MySupplier.Id > Vendor.Id. This is a classic Table-per-type (TPT) inheritance strategy.

After upgrading to NopCommerce 4.50.4 the new install of the site creates MySupplier table which has all attributes of MySupplier + Vendor in a single table, which is Table-per-Hierarchy Inheritance strategy.

Based on linq2db documentation, it does not support Table-per-type inheritance strategy. So I'm unclear why this even worked in 4.40.4 and I cannot find what has changed in 4.50.x that caused the different behaviour. But something clearly changed as the system expect MySupplier Table to have all the fields found in Vendor class which was not the case before the upgrade.
7 месяцев назад
nopcommerce team, can you please share your insights?
7 месяцев назад
(I'm not on the Team, but here are my thoughts...)

I don't know what's changed from 4.40 to 4.60 that would impact the way the tables are created.  I do note this in the release notes for 4.60:
#6294 Bump LINQ to DB to 4.1.0

Yes, I guess the nopCommerce entities to DB looks more like TPH, however, I think the consideration here is that nopCommerce is not using a "inheritance strategy/model".  It's using Entity-Relationship Modeling.  There are no "hierarchies".  The before mentioned Product table inheriting from BaseEntity, IAclSupported, and ISoftDeletedEntity to use those "common" properties seems more like composition.

In 4.30, nopC moved from EF to Linq2DB.  If you were to Diff the \Libraries\Nop.Core\Domain folders between 4.20 and 4.30 you would see that they removed all the "Navigation properties" i.e., removed all the "public virtual ...".  You should consider doing the same.   (Which maybe you did based on your answer to this post)