34

I have two tables - "Customer" table and "Blacklist" customer table. When I blacklist a customer, I put the CusId as a foreign key into to Blacklist table.

What I want to do is get CusId and Name that are not in the BlackList Table.

How can I achieve this in Entity Framework C#?

Customer
---------
(CusId,Name,Telephone,Email)

Blacklist
---------
(CusId)
1
  • I am new to EF and I hv already tried variours ways. None of them did work. So please help me to fix this matter. Commented Feb 13, 2014 at 22:31

5 Answers 5

80

What you want is something like the following:

db.Customers
    .Where(c => !db.Blacklists
        .Select(b => b.CusId)
        .Contains(c.CusId)
    );

EF will happily turn that into a sub-query that will run quite well.

This pattern works for static lists (creates an IN(a, b, c) expression) as well as other tables. You can use it to check for being in the list or not in the list.

If you want to test it and see the SQL it generates, I strongly recommend LINQPad (it is free). That's what I use to test out little ideas in LINQ all the time.

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

4 Comments

could you provide a "verbose" version (like in the answer provided by Tim below) of the statement you have above? that would really help out. Or if you know of a place to convert from one to another that would be even better :)
How can you add another Where clause? for instance Where Customer.Email =='[email protected]' ??
VERY SLOW: If Blacklists table have 1 million records, it will not work because it will always give error of time out
Shorter version: db.Customers.Where(c=>!db.Blacklists.Any(b=>b.CusId==c.CusId)). However, same SQL expression will be generated by Entity Framework.
6

How about something like this:

var subselect = (from b in BlackList select b.CusId).ToList();

var result = from c in Customer where !subselect.Contains(c.CusId) select c;

6 Comments

Is there any reason why you'd want to do things this way rather than the way Timothy shared?
@PeterMajeed well, I'm not sure, but Tim only fetches BlackList once. Timothys BlackList is encased in a Where (but it could be that EF optimizes that so that it is only fetched once as well)
A quick check I did showed that for my code the BlackList table was added as a WHERE NOT EXISTS (SELECT NULL AS [Empty] FROM [Blacklist] ... so it doesn't even retrieve it, SQL does all the work and it is nicely optimized.
Sorry guys. I just offered the above as something I've used before. When I posted my answer, I hadn't yet seen any other answers.
@TimRolen All good mate, there are times when your solution is handy, and it definitely works. Just good to be aware that EF will convert it into a WHERE CusId NOT IN (1, 2, 3, 4) type of statement. For short lists or where there's extra logic to filter the lists that is the best solution, use it myself often too.
|
5

Any() is the best performance :

db.Customers.Where(c => !db.Blacklists.Any(b => b.CusId == c.Id));

If you also need columns of Blacklists , use join with condition : b.CusId == c.Id

Comments

1

IF in table BlackList yo have a List of Customer You can perform something like

 IEnumerable<Customer> model = (from c in db.Customer
                                from b in c.BlackList.DefaultIfEmpty()
                                 where b.CusID== null
                                  select new Customer
                                   {
                                        CusId= c.OrderID
                                    }).ToList();

Comments

0

This query I used and it works perfectly:

var query = _context.Customer.Where(x => x.Id == id && !x.BlackList.Any(z => x.Id == x.CustId)).ToList();

Comments

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.