Entity Framework error using DefaultIfEmpty() - c#

I have a problem with Entity Framework using the DefaultIfEmpty method. The following query is returning empty when it should return an offer that matches all criteria in the database.
If I remove one or both DefaultIfEmpty method calls it works, but with them it doesn't. I need those to prevend another problem in the query.
When I execute the generated SQL query directly on the database it works and it returns the offer.
I also made an Unit Test reproducing the same example and it also passes so it must be an Entity Framework issue.
Here's the query:
private static Expression<Func<Offer, bool>> AddFilter(Service criteria)
{
return offer => offer.Restrictions.
SelectMany(rest => rest.OperatorRange.DefaultIfEmpty(), (rest, alop) => new { Restriction = rest, OperatorRange = alop.Id }).
Where(alop => criteria.ServiceUseNet == null || alop.OperatorRange.ToUpper() == criteria.ServiceUseNet.ToUpper()).
SelectMany(rest => rest.Restriction.CallType.DefaultIfEmpty(), (rest, till) => new { Restriction = rest, CallType = till.Id }).
Any(till => criteria.UseServiceCoverage == null || till.CallType.ToUpper() == criteria.UseServiceCoverage.ToUpper());
}

Change it into two Any calls:
return offer => offer.Restrictions
.Any(rest
=> rest.OperatorRange
.Where(alop => criteria.ServiceUseNet == null
|| alop.OperatorRange.ToUpper() == criteria.ServiceUseNet.ToUpper())
.Any(till => criteria.UseServiceCoverage == null
|| till.CallType.ToUpper() == criteria.UseServiceCoverage.ToUpper()));
The predicate is supposed to test whether there are any OperatorRanges (meeting some criteria) having any CallTypes meeting some criteria. If there are no OperatorRanges, there won't be any CallTypes either, let alone matching CallTypes.
In this form, the predicate always returns true or false.

Related

EF linq query where condition based on bool parameter

I have an EF linq query where I want to set a where condition based on a true/false parameter. I can do something similar in SQL which is somewhat how I've written my EF query but it doesnt seem to work with EF Core.
When I expect the executed SQL if I pass "activeOnly = true" then no SQL where condition is applied and when I pass "activeOnly = false" then the condition is "where 0 = 1".
Clearly I have this wrong but I cant figure out the right way to do this? Or if its possible?
public async Task<List<UserDto>> GetUsersAsync(string region, bool activeOnly)
{
var allUsers = new List<UserDto>();
var countries = _configuration.GetRegionConfiguration(region).Countries;
foreach (var country in countries)
{
_context.ChangeConnectionString(country.DatabaseConnectionString);
var users = await _context.User
.ProjectTo<UserDto>(_mapper.ConfigurationProvider)
.Where(x => (activeOnly && (x.RoleIds != null)) || (!activeOnly && (x.RoleIds == null)))
.ToListAsync();
allUsers.AddRange(users);
}
allUsers.OrderBy(x => x.FullName);
return allUsers;
}
Current versions emit a helpful warning when you use this kind of query:
Collection navigations are only considered null if their parent entity is null. Use 'Any' to check whether collection navigation 'YourEntity.YourNavigationColleciton' is empty.
So instead of
x.RoleIds != null
use
x.RoleIds.Any()

How to make reusable conditions that can be used in queryables? [duplicate]

This question already has answers here:
How to reuse where clauses in Linq To Sql queries
(4 answers)
Closed 1 year ago.
So in a function I've a large queryable and I apply a bunch of where cause on it based on other conditions.
Like in this example:
query.Where(i =>
_context.FicDernierEvt
.Where(y => y.VteAffaire == null && y.ApvAffaire == null)
.Select(y => y.IdFicheCrm)
.Contains(i.Id)
);
I've this condition _context.FicDernierEvt.Where(y => y.VteAffaire == null && y.ApvAffaire == null).Select(y => y.IdFicheCrm).Contains(i.Id) that is used a lot in my code.
I would like to avoid having this all accross my code so i've tried to make a function:
private bool isProspect(FicFicheCrm ficheCrm){
return _context.FicDernierEvt
.Where(y => y.VteAffaire == null && y.ApvAffaire == null)
.Select(y => y.IdFicheCrm)
.Contains(ficheCrm.Id);
}
So i could use it this way:
query.Where(i => isProspect(i));
But it didn't worked since, it's just not mean to be done that way.
Do someone have an idea on how to make reusable conditions like this to be used in queryables ?
My advice would be to extend LINQ with a Where method that contains your predicate.
If you are not familiar with Extension methods, consider to read Extension Methods Demystified
You fogrot to tell us what type of IQueryable<...> you store in _context.FicDernierEvt, but let's assume it is IQueryable<FicDernierEvt>. In other words, assume that _context.FicDernierEvt is a table of FicDernierEvts.
Requirement Procedure GetIdFics (TODO: invent proper name) takes as input an IQueryable<FicDernierEvt>, keeps only those ficDernierEvts that have a null value for both properties VteAffaire and ApvAffaire, and returns from every remaining ficDernierEvt the value of property ficDernierEvt.IdFic
I don't know the type of IdFic, but let's assume it is an int
public static IQueryable<int> GetIdFics( // TODO: invent proper name
this IQueryable<FicDernierEvt> source)
{
return source.Where(ficDernierEvt => ficDernierEvt.VteAffaire == null
&& ficDernierEvt.ApvAffaire == null)
.Select(ficDernierEvt => ficDernierEvt.IdFic);
}
That's all!
Usage:
IQueryable<int> myIdFics = _context.FicDernierEvt.GetIdFics();
You say you have this Where/Select in a lot of places:
var oldIdFics = _context.FicDernierEvt
.Where(ficDernierEvt.Date.Year < 2010)
.GetIdfics();
var invalidIdFics = _context.FicDernierEvt.GetIdFics()
.Where(idFic => idFic <= 0);
You can even use it in a more complicate LINQ statement:
IQueryable<FicDernierEvt> unpaidFicDernierEvts = this.GetUnpaidFicDernierEvts();
int customerId = this.GetCustomerId(customerName);
var largestUnpaidCustomerIdFic = unpaidFicDernierEvts
.Where(unpaidEvt => unpaidEvt.CustomerId == customerId)
.GetIdFics()
.Max();

Make and Expression available to be used within a Linq to EntityFramework Expression

I have the following LINQ Expression that I need to be able to use within a LINQ to Entities query.
There is currently a property like this:
[NotMapped]
public Clinic CurrentClinic
{
get { return AdmissionRoot.CurrentFacility.Compile()(this); }
}
Which called the following:
public static Expression<Func<Admission, Clinic>> CurrentFacility =
a => a.Person.PersonLocations.Any(p => p.Clinic.FacilityType != (int)Clinic.FacilityTypes.CommunityServices)
? a.Person.PersonLocations.Where(p => p.Clinic.FacilityType != (int)Clinic.FacilityTypes.CommunityServices)
.OrderByDescending(l => l.TransferDate)
.ThenByDescending(l => l.LocationId)
.FirstOrDefault().Clinic
: a.Clinic;
The issue is that I cannot use CurrentClinic within a LINQ to Entities statement because it will give the following error:
"The specified type member 'CurrentClinic' is not supported in LINQ to
Entities"
I am new to LINQ to Entities expressions and was hoping someone would be able to refactor this so it can be used within a LINQ to Entities statement something like this:
Db.Admissions.Where(
a =>
(a.CurrentClinic != null
&& !a.CurrentClinic.Company.IsHomeCompany
&& a.ReferralClinicId == clinicid
)
||
(a.CurrentClinic.Company.IsHomeCompany
&& a.CurrentClinic.ClinicId == clinicid
)
);
If it can't be done in an Expression that I can "add" other criteria onto the end then is there another way/suggestion that would work without compromising speed too much?
The issue here is because you're using CurrentClinic in your query which is not something that Entity framework can turn into an expression. A possible alternate way to run your query could be
Db.Admissions
.Select(a => new
{
CurrentClinic = CurrentFacility(a),
Admission = a
})
.Where(a =>
(a.CurrentClinic != null && !a.CurrentClinic.Company.IsHomeCompany && a.Admission.ReferralClinicId == clinicid) ||
(a.CurrentClinic.Company.IsHomeCompany && a.CurrentClinic.ClinicId == clinicid));
Note: this is untested but should still work.

Is this a bad Moq setup or a deficiency in Moq?

I am attempting to test the following code:
public async Task<Activity> Get(long ID, Recruiter User, bool IsArchived = false)
{
Activity result = await collection.FirstOrDefault(x => x.ID == ID && x.Recruiter.CompanyID == User.CompanyID && (!x.Archived || IsArchived));
return result;
}
With the following test:
[TestMethod]
public async Task GetDoesThings()
{
long ID = 1;
bool IsArchived = false;
Recruiter User = new Recruiter()
{
CompanyID = 1
};
ActivitiesMock.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))).ReturnsAsync(new Activity());
Activity result = await repo.Get(ID, User);
ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));
}
(I know there are different ways of writing it, this is the most recent iteration we've tried.)
The ActivitiesMock relates to the collection found in Get(long ID, Recruiter User, bool IsArchived = false). We recently wrote wrappers in order to try and test our Entity calls more efficiently, but we're running into this error when trying to verify the calls are made correctly:
Test method ExampleProject.Tests.Backend.Repositories.ActivityRepositoryTests.GetDoesThings threw exception:
Moq.MockException:
Expected invocation on the mock at least once, but was never performed: x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived))
Configured setups:
x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived)), Times.Never
Performed invocations:
IAppCollection`2.FirstOrDefault(x => (((x.ID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).ID) AndAlso (x.Recruiter.CompanyID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).User.CompanyID)) AndAlso (Not(x.Archived) OrElse value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).IsArchived)))
In this instance the wrapper (collection) is a mock of the interface. The goal is to ensure that the repository is calling the correct expression on the wrapper, so that we know the predicate that's being passed to the Entity DbSet is correct without having to worry about all the messy async abstractions.
The Mock Setup() with the full predicate doesn't appear to be found when the test is ran, and when I change the Setup() to It.IsAny<Expression<Func<Activity, bool>>>() it runs the mock and provides the return, but the Verify call doesn't work. So, running:
ActivitiesMock.Setup(x => x.FirstOrDefault(It.IsAny<Expression<Func<Activity, bool>>>())).ReturnsAsync(new Activity());
Activity result = await repo.Get(ID, User);
Assert.IsNotNull(result);
ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));
Passes the assert but fails the Verify, whereas running:
ActivitiesMock
.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)))
.ReturnsAsync(new Activity())
.Verifiable();
Activity result = await repo.Get(ID, User);
Assert.IsNotNull(result);
ActivitiesMock.Verify();
Fails on the assert.
It looks like it's failing because it's expecting the same object types. Am I trying to do something that Moq can't handle, or am I missing something that I need to do in order to get the verification to be correct?
By request, the concrete implementation of the LINQ-to-Entity wrapper (collection) is:
public Task<T> FirstOrDefault(Expression<Func<T, bool>> Predicate)
{
return DbSet.FirstOrDefaultAsync(Predicate);
}
Though the wrapper itself isn't being used, but an interface for it is being mocked, and it's that mock that we're testing.
The answer is neither. Since the anonymous functions have to create class instances to store the data being provided, they create DisplayClass instances to hold the data. Since those instances are being created in different namespaces (among other things) they don't pass when Moq calls .Equals against them.
We solved this problem by writing our tests as such:
ActivitiesMock
.Setup(x => x.Where(It.IsAny<Expression<Func<Activity, bool>>>()))
.Returns((Expression<Func<Activity, bool>> x) =>
{
actualPredicate = x;
return queryMock.Object;
});
Then creating valid and invalid activities to provide to the predicate to ensure it returns true or false correctly:
Assert.IsTrue(actualPredicate.Compile().Invoke(validActivity));
Granted for now it's a bit hacky, but at first glance it doesn't seem too much like a dumpster fire solution, and it's a way for us to ensure the calls being provided do what we expect them to, which is what we want.
Update (Sep 7th, 2016): So far this has been working well for us. We've ran into an issue where LINQ-to-Entity statements don't run as expected because the LINQ is case-sensitive and the SQL generated isn't, but since that isn't a deal breaker for us we're just fine.

Test for List<T> membership using a List<T>

Does anyone know if there is a way to test for list membership utilizing a list. For example I have a class named Membership which has a property Rebates which is of type List<Enums.RebateType>. I want to test using a lambda expression to see if that list contains any rebates that are of a specific type. My orginal lambda expression is as follows
return Membership.Rebates.Exists(rebate =>
rebate.RebateType == Enums.RebateType.A &&
rebate.RebateStatus == Enums.RebateStatus.Approved);
Instead of having to do the following:
return Membership.Rebates.Exists(rebate =>
(rebate.RebateType == Enums.RebateType.A &&
rebate.RebateStatus == Enums.RebateStatus.Approved) ||
(rebate.RebateType == Enums.RebateType.B &&
rebate.RebateStatus == Enums.RebateStatus.Approved));
I was wondering if something similar to the following mocked up SQL syntax could be done via one Lambda expression.
SELECT COUNT(*)
FROM Membership.Rebates
WHERE RebateType IN (ValidRebateTypes) AND Approved = true
ValidRebateTypes is curently a List<Enums.RebateType> that I am testing for i.e. ValidRebateTypes = (Enums.RebateType.A, Enums.RebateType.B).
The work around I currently have is as follows:
bool exists = false;
foreach (Enums.RebateType rebateType in ValidRebateTypes())
{
exists = Membership.Rebates.Exists(
rebate =>
rebate.RebateType == rebateType &&
rebate.RebateStatus == Enums.RebateStatus.Approved);
if (exists) { break; }
}
return exists;
Sounds like you want:
Membership.Rebates.Where(r => ValidRebateTypes.Contains(r.RebateType)
&& r.RebateStatus == Enums.RebateStatus.Approved);
You can then use .Count() for the count:
Membership.Rebates.Where(r => ValidRebateTypes.Contains(r.RebateType)
&& r.RebateStatus == Enums.RebateStatus.Approved)
.Count();
Or .Any() to determine the existence of any that satisfy that condition
Membership.Rebates.Any(r => ValidRebateTypes.Contains(r.RebateType)
&& r.RebateStatus == Enums.RebateStatus.Approved);
In addition to Marc's suggestion, I would recomment making ValidRebateTypes a HashSet<Enums.RebateType>. Not only is this likely to be more efficient (although possibly not for a small set), it also reveals your intent (ie. that there only be one of each value of RebateType in it).

Categories

Resources