We have introduced a new feature in our application, that affects hundreds of queries. We have to set a bool
field to indicate if the license is valid, in a very complicated way.
I would like to create a method for returning this bool
value, and I'd like to use it in every query. The problem is, that if I use it in the way shown below, it executes a separate query for each result.
How do I use the Expression
in a way that it is compiled into SQL and executed as a single query?
Original query, in need of improvement
IQueryable<DeviceMinimal> devices =
from device in db.Devices
where device.AccountId = accountId
select new DeviceMinimal
{
Id = device.Id,
Name = device.Name,
LicenseIsValid = !checkForLicense ||
device.License != null && (
!device.License.TrialStarted
// && 12+ licensing rules
)
};
checkForLicense
is a bool
that indicates that license does not need to be checked. It is used in some cases and it is necessary to be considered.
Code, that solves the problem, but provokes a separate query for each device
IQueryable<DeviceMinimal> devices =
from device in db.Devices
where device.AccountId = accountId
select new DeviceMinimal
{
Id = device.Id,
Name = device.Name,
LicenseIsValid =
LicenseHelper.IsLicenseValid(checkForLicense).Invoke(device)
};
The method use in the query above:
public static Func<Device, bool> IsLicenseEnabledAndValid(bool checkForLicense)
{
return result => !checkForLicense ||
result.License != null && (
!result.License.TrialStarted
// && 12+ licensing rules
);
}
If you set the DataLoadOptions
of the DataContext
before the query and setup them right, you should avoid the subselect. Something similar to this:
db.LoadOptions.LoadWith<Devices>(p => p.License);
Tha is the default behaviour (lazy loading of the entities). You could have for more info searching for 'linq to sql eagerloading'
Not sure if it will work, but did you try accessing the licence in the main query? In other words something like :
Queryable<DeviceMinimal> devices =
from device in db.Devices
where device.AccountId = accountId
select new DeviceMinimal
{
Id = device.Id,
Name = device.Name,
LicenseIsValid =
LicenseHelper.IsLicenseEnabledAndValid(checkForLicense).Invoke(device.Licence)
};
public static Func<License, bool> IsLicenseEnabledAndValid(bool checkForLicense)
{
return result => !checkForLicense ||
result != null && (
!result.TrialStarted
// && 12+ licensing rules
);
}
If you need to access both the device and Licence in your method, you might need to change the function to be something like
public static Func<Device, License, bool> IsLicenseEnabledAndValid(bool checkForLicense)
{
return (device, licence) =>
...
}
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.