简体   繁体   中英

More efficient way of loading children of entity objects in linq to entity query

I have a rather complex linq to entity query that I'm performing, in the end, I have a result set. I loop through that result set, build business objects and return that list of business objects. it's pretty quick, the problem is that 2 of the child properties are complex objects with their own child objects. for every business object in my loop, I then have to make 2 DB calls to fill its child object. Those 2 calls slow down the overall process, is there a better way to do this? noob to EF here. (EF 4,SQL Server 2008,c#)

Get a result set:

var newresult = from r in result // result is another complex query
            join subedit in
                (from sa in context.Security_Access
                 join g in context.Security_UserGroup on sa.EntityID equals g.GroupID
                 where (sa.PrivledgeID == xx) && g.UserID == userId
                 select new { user = g.UserID, linkid = sa.LinkID }).Distinct() on new { aid = r.AssetId } equals new { aid = subedit.linkid } into theSubEdit
            from subEditAccess in theSubEdit.DefaultIfEmpty()
            join subdownload in
                (from sa in context.Security_Access
                 join g in context.Security_UserGroup on sa.EntityID equals g.GroupID
                 where (sa.PrivledgeID == xx|| sa.PrivledgeID == yy) && g.UserID == userId
                 select new { user = g.UserID, linkid = sa.LinkID }).Distinct() on new { aid = r.AssetId } equals new { aid = subdownload.linkid } into theSubDownload
            from subDownloadAccess in theSubDownload.DefaultIfEmpty()
            join subView in
                (from sa in context.Security_Access
                 join g in context.Security_UserGroup on sa.EntityID equals g.GroupID
                 where (sa.PrivledgeID == xx|| sa.PrivledgeID == yy|| sa.PrivledgeID == 101) && g.UserID == userId
                 select new { user = g.UserID, linkid = sa.LinkID }).Distinct() on new { aid = r.AssetId } equals new { aid = subView.linkid } into theSubView
            from subViewAccess in theSubView.DefaultIfEmpty()
            select new { r, EditAccess = (int?)subEditAccess.user, DownloadAccess = (int?)subDownloadAccess.user, ViewAccess = (int?)subViewAccess.user };

I then loop through that result set:

foreach (var asset in newresult)
{
    // and build a new business object, set its properties
    BoAsset boAsset = new BoAsset();
    boAsset.HasEditRights = (asset.EditAccess > 0);
    boAsset.HasDownloadRights = (asset.DownloadAccess > 0);
    boAsset.HasViewRights = (asset.ViewAccess > 0);
    boAsset.Description = asset.r.Description;
    boAsset.DetailedDescription = asset.r.DetailedDescription;
    boAsset.Keywords = asset.r.Keywords;
    boAsset.Notes = asset.r.Notes;
    boAsset.Photographer = asset.r.Photographer;
    boAsset.PhotographerEmail = asset.r.PhotographerEmail;
    boAsset.Notes = asset.r.Notes;
    boAsset.Author = asset.r.Author;

    // these 2 properties i've commented out are 
    // complex objects/entities, setting them the way I am 
    // requires me to call 2 separate methods which make 2 DB trips
    // per business object.

    //boAsset.Domains = GetAssetDomains(asset.r.AssetId);
    //boAsset.DomainEntries = GetAssetCustomDomains(asset.r.AssetId);

    myListofObjects.Add(boAsset);
}
 return myListofObjects;

Is there a better way?

Just add this .Include("Domains").Include("DomainEntries") to your Linq in in context.Security_Access That should get rows from those tables all in one go.

So your "inner" queries would look like:

from sa in context.Security_Access.Include("Domains").Include("DomainEntries")
join g in context.Security_UserGroup on sa.EntityID equals g.GroupID
where (sa.PrivledgeID == xx) && g.UserID == userId
select new { ...

Here is the documentation from MS: http://msdn.microsoft.com/en-us/library/bb738708.aspx

If you want to improve your performance use compile queries !

You can check the example here.

 static readonly Func<AdventureWorksEntities, Decimal, 
 IQueryable<SalesOrderHeader>> s_compiledQuery2 =
 CompiledQuery.Compile<AdventureWorksEntities, Decimal, IQueryable<SalesOrderHeader>>((ctx, total) => 
from order in ctx.SalesOrderHeaders.Include("Orders") where order.TotalDue >= total select order);

MSDN

AND

You can Introduce Include suppose to select all the employees along with their departments . If you have a navigational property, you won't need a join at all. You can use Include like this:

List<Employee> employeesWithDepartments = CreateObjectSet<Employee>().
                                      Include(e => e.Department).
                                      ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM