Reputation: 6626
Using Linq and EF
One User
can have many RoleUserLinks
.
If a User
's RoleUserLink
table contains 2 records - one which has a LinkStatusID
of Deleted
and one which has a LinkStatusID
of Added
, the query below returns the User
. I don't want this.
How to not return the user
if there are any associated LinkStatusID
's of Added
see case 3 below
IEnumerable<User> z =
(from users in listOfUsersForReviewer
join roleUserLinks in context.RoleUserLinks
on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
// left join
from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
where
// case 1 - has never been added to a role ie record isn't there
roleUserLinks.LinkStatus == null
// case 2 - has been soft deleted from a role so we want this record
|| roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Deleted
select users).Distinct();
case 1) User has no associated RoleUserLink
records. user is returned as expected
case 2) User has 1 associated RoleUserLink
record with LinkStatusID
of Deleted. user is returned as expected
case 3) User has 2 associated RoleUserLink
records. 1 has a LinkStatusID
of Deleted. user should not be returned
Upvotes: 1
Views: 145
Reputation: 5666
If I understand it well it should be:
IEnumerable<User> z =
(from users in listOfUsersForReviewer
join roleUserLinks in context.RoleUserLinks
on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
// left join
from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
where
(roleUserLinks == null
|| roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Deleted)
&& !roleUserLinksJoin.Where(x=> roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Added && x.UserID == roleUserLinks.UserID).Any()
select users).Distinct();
I have added this subquery:
&& !roleUserLinksJoin.Where(x=> roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Added && x.UserID == roleUserLinks.UserID).Any()
It will remove unwanted rows from result with users which has record in RoleUserLinks
with LinkStatusId
Added
.
I have also changed this roleUserLinks.LinkStatus == null
to roleUserLinks == null
to avoid NullReferenceException
in case there will be no matching RoleUserLink
for User
Sample code on which I tested my code
static void Main(string[] args)
{
var usersList = new List<User>()
{
new User() {UserID = 1},
new User() {UserID = 2},
new User() {UserID = 3}
};
var userLinksList = new List<RoleUserLink>()
{
new RoleUserLink() {UserID = 1, State = "del"},
new RoleUserLink() {UserID = 2, State = "add"},
new RoleUserLink() {UserID = 2, State = "del"}
};
IEnumerable<User> z = (from users in usersList
join roleUserLinks in userLinksList
on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
// left join
from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
where
// has never been added to a role ie record isn't there
roleUserLinks == null
// has been soft deleted from a role so we want this record
|| roleUserLinks.State == "del"
// has been added to role so we don't want this record
&& !roleUserLinksJoin.Where(x=> x.State == "add" && x.UserID == roleUserLinks.UserID).Any()
select users).Distinct();
var res = z.ToList();
}
public class User
{
public int UserID { get; set; }
}
public class RoleUserLink
{
public int UserID { get; set; }
public string State { get; set; }
}
It returns user with id 1 and 3. As I expected. UserId:1
has only link with status delete
. UserId:3
does not have any link. And UserId:2
is not returned because it has also link with status add
.
Upvotes: 1
Reputation: 6626
I solved this problem by taking the original query:
IEnumerable<User> z =
(from users in listOfUsersForReviewer
join roleUserLinks in context.RoleUserLinks
on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
// left join
from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
where
// case 1 - has never been added to a role ie record isn't there
roleUserLinks.LinkStatus == null
// case 2 - has been soft deleted from a role so we want this record
|| roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Deleted
select users).Distinct().Include(b => b.RoleUserLinks).ToList();
and added the Include and ToList at the end.
Then:
var list = new List<User>();
foreach (var user in z)
{
bool shouldReturnUser = true;
//get roleLinks
foreach (var rul in user.RoleUserLinks)
{
if (rul.LinkStatusID == (byte) Enums.LinkStatus.Added)
shouldReturnUser = false;
}
if (shouldReturnUser)
list.Add(user);
}
then returning this list.
I understand there is a perf hit by doing this, and processing on the webserver, but IMHO this is very easy to understand, and it works :-)
Upvotes: 0