0

I have a method that queries the database using Entity Framework, and returns the EF object (ApplicationUser). If I have a constructor for ApplicationUser that tries to use this method to populate its properties, will the complex properties of that object trigger the database to be called when they are set? In the original object they are proxies, and therefore would be lazy loaded, but will merely setting those properties to properties of a new instance of the same object call the database?

Here's a simple example:

public class ApplicationUser
{
    public ApplicationUser(int userId)
    {
        ApplicationUser user = ApplicationUser.Select(userId);
        this.FirstName = user.FirstName //this is fine
        this.ApplicationRole = user.ApplicationRole //This is a complex object. Is it still going to be lazily loaded and called only if this.ApplicationRole is referenced?
    }

    public static ApplicationUser Select(int userId)
    {
        //this uses EF to return an Application User object
    }
}
2
  • If there is a foreign key between your user and role, you basically set the same ID_ROLE for both user objects. Commented Sep 16, 2015 at 19:13
  • There is a foreign key set. The idea is for them to be set the same, but my question is, will just setting the complex properties of the new EF/Business Object to the original EF object's complex properties, cause the database to be queried for those virtual (FK) properties? Commented Sep 16, 2015 at 19:17

1 Answer 1

2

The database will be called in this line:

this.ApplicationRole = user.ApplicationRole;

Then, your object will be fetched and will not be lazy loaded any more.

To make sure that this will happen, you have to do some configuring:

  1. lazy loading and proxy creation must be enabled:

    public Context()
        : base("YourConnectionString")
    {
        Configuration.LazyLoadingEnabled = true;
        Configuration.ProxyCreationEnabled = true;
    }
    
  2. Navigation properties must be declared as virutal:

    public class ApplicationUser
    {
        //...
        public virtual ApplicationRole ApplicationRole { get; set; }
        //...
    }
    

EXAMPLE IN ACTION

Supposed that you have these classes

public class ApplicationUser
{
    public int ApplicationUserId { get; set; }
    public string FirstName { get; set; }
    public virtual ApplicationRole ApplicationRole { get; set; }

    public static Context db { get; set; }

    public ApplicationUser()
    {

    }

    public ApplicationUser(int userId)
    {
        ApplicationUser user = ApplicationUser.Select(userId);
        this.FirstName = user.FirstName; 
        this.ApplicationRole = user.ApplicationRole; //database will be hit here
    }

    public static ApplicationUser Select(int userId)
    {
        //this uses EF to return an Application User object
        return db.Users.Find(userId);
    }
}

public class ApplicationRole
{
    public int ApplicationRoleId { get; set;}
    public string Name { get; set; }
}

First Hit:

return db.Users.Find(userId);

Generated SQL:

SELECT
    [Limit1].[ApplicationUserId] AS [ApplicationUserId],
    [Limit1].[FirstName] AS [FirstName],
    [Limit1].[ApplicationRole_ApplicationRoleId] AS [ApplicationRole_Application
RoleId]
    FROM ( SELECT TOP (2)
        [Extent1].[ApplicationUserId] AS [ApplicationUserId],
        [Extent1].[FirstName] AS [FirstName],
        [Extent1].[ApplicationRole_ApplicationRoleId] AS [ApplicationRole_Applic
ationRoleId]
        FROM [dbo].[ApplicationUsers] AS [Extent1]
        WHERE [Extent1].[ApplicationUserId] = @p0
    )  AS [Limit1]

-- p0: '1' (Type = Int32)

Second Hit

this.ApplicationRole = user.ApplicationRole

Generated SQL

SELECT
    [Extent2].[ApplicationRoleId] AS [ApplicationRoleId],
    [Extent2].[Name] AS [Name]
    FROM  [dbo].[ApplicationUsers] AS [Extent1]
    INNER JOIN [dbo].[ApplicationRoles] AS [Extent2] ON [Extent1].[ApplicationRo
le_ApplicationRoleId] = [Extent2].[ApplicationRoleId]
    WHERE ([Extent1].[ApplicationRole_ApplicationRoleId] IS NOT NULL) AND ([Exte
nt1].[ApplicationUserId] = @EntityKeyValue1)


-- EntityKeyValue1: '1' (Type = Int32, IsNullable = false)

If the ApplicationRole object has other navigation properties, they will still be lazy-loaded, without problems.


Here comes a tip that might be helpful. To see when EF is hitting the database, create a console app, add a reference of your solution, and use the context.Database.Log. To see more about logging, take a look at this link https://msdn.microsoft.com/en-us/data/dn469464.aspx

Sign up to request clarification or add additional context in comments.

4 Comments

So is there a way to prevent it from loading when I do this.ApplicationRole = user.ApplicationRole. I don't want it to call the database, I simply want it to transfer the proxy to the new object, so that it may have a connection for lazy loading.
Also, how did you profile that database call on the (this.ApplicationUser = user.ApplicationUser) line?
Instead of passing the Id in the object's constructor, you can create a static method which returns the entire object. So, the proxies will be transferred to the object
Yeah, that is what I am going to do. I was just hoping I might be able avoid it, since the constructor is being used all over the code already. This is an older project, being upgraded to use Entity Framework, and I was trying to avoid doing too much refactoring, but it seems like that is what is necessary in this case. Thank you for all of your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.