LINQ (LAMBDA) How do I add another list of objects to my Where? c#

Asked

Viewed 452 times

1

Good afternoon, I’m running a C# Net Core application, using lambda for database context handling. I have one question, and that is: I have a list of objects with these two attributes: Name and Startdate. Something like:

List<Operations> operations = new List<Operations>();
operations.Add(new Operation() { Name: "Exemplo 1", StartDate: "2018-07-02 00:00:00" };
operations.Add(new Operation() { Name: "Exemplo 2", StartDate: "2017-05-01 13:00:00" };

Now I would like to do a lambda in my context, iterating this list with a condition with the operator "OR". Something that would look like this in SQL:

SELECT
    *
FROM
    contact t
WHERE
    (t.OperationName = "Exemplo 1" AND t.ContactDate > "2018-07-02 00:00:00")
    OR (t.OperationName = "Exemplo 1" AND t.ContactDate > "2017-05-01 13:00:00")

But I’m not getting it. The conditions within the parentheses are separated by AND, when they relate to the same object, and separating the objects by OR. I’m using Lambda, something as follows below:

dbContext.Teste.Where(x => x...);

@EDIT: A Fiddle I made to demonstrate my problem: https://dotnetfiddle.net/DqvOx4

In this Fiddle, I can only do Where with the first obj of Operations, but I need to iterate through all objects. Does anyone have any idea how to do this using Lambda?

  • You have already written the answer with the solution. We do not write answers in the questions, nor do we put "solved" in the title

  • Right, and as I mark that question has been resolved?

  • You already did when you marked your own response with the green old. See more here

2 answers

0

To use AND and OR with lambda the operator is used && and ||

Let’s assume you have next class:

public class Operation
{
    public string Name { get; set; }
    public DateTime StartDate { get; set; }
}

With this we can create (Simulating database data) a list of operations as follows

List<Operation> operations = new List<Operation>
{
    new Operation() { Name= "Exemplo 1", StartDate= Convert.ToDateTime("2018-07-02 00:00:00") },
    new Operation() { Name = "Exemplo 2", StartDate= Convert.ToDateTime("2017-05-01 13:00:00") },
    new Operation() { Name = "Exemplo 3", StartDate= Convert.ToDateTime("2016-05-01 13:00:00") }
};

Now we will do a search in this list and throw the selected data in another list as follows

List<Operation> operationsDois = operations.Where(x => (x.Name == "Exemplo 1" && x.StartDate == Convert.ToDateTime("2018-07-02 00:00:00")) || (x.Name == "Exemplo 2" && x.StartDate == Convert.ToDateTime("2017-05-01 13:00:00"))).ToList();

Here an example searching by date, will pick from the last 30 days

List<Operation> operationsTres = operations.Where(x => x.StartDate >= DateTime.Now.AddDays(-30) && x.StartDate <= DateTime.Now).ToList();

With this the second list has researched information.


When it’s made a Where it will go through all the dice checking which ones you will "marry", to play it on a list you can do something more or less like this:

List<Teste> testes = dbContext.Teste.Where(x => (x.Name == "" && x.StartDate == "") || (x.Name == "" && x.StartDate == "")).ToList();
  • Right, but how do I do for all the objects in the list? In this example you would only be 2 objects. How do I apply something like a for-each in the list?

  • I edited the answer, see if it was clearer, the where will pass in all data of the list, having 2 or more

  • I guess it’s still not the way I need to... For you to understand, both the Operation class and the Test object of the database have the same parameters. So I want to search all the test objects that match the filter of the objects of Operations, get it? The way you did n is exactly that.

  • I don’t understand.. You have two objects with the same fields and want to search both 1 and the other with the same search "terms"? the last line of code I added is the same as the query sql that you added to the question

  • To put you in context: I have a list of registered operations, which will serve as a parameter for my search in the Test class. The test class has several other attributes, besides the ones that the operation class also has, I want to perform a filter in the Test class on all the objects that contain the information from the list of operations that I picked up. The only problem with your line of code, unless I’m wrong, it’s only iterating 2 objects in condition, but this list of operations can, and will have much more than two objects.

  • Take a look at this Fiddle, I have created a list of 6 items and am making a Where to return me only 2 data. table in database can have thousands of data, when it is done lambda Where will return only information that "match" with what was searched.

  • It will not iterate only 2 objects, but two object fields, if I do p=> p.Name = "Exemplo" will return all items that have the Name Example, be it 1 or 100 items. I think I’m getting what you want.. you’re doing something like Join? example where Test.Name = Operation.Name?

  • Look, I’m sorry, but I think I got it wrong. I made a Fiddle to give you an idea of what I want to do: https://dotnetfiddle.net/DqvOx4 In the "Resulted list" I want to find all the contacts, but using the operation objects as a filter. In this case I only searched the first one in the Operations list, using Firstordefault. I want to iterate on all objects in that list. I could understand?

  • Confirm this, please https://dotnetfiddle.net/grAVrg. I only removed the last filter because it had no match, but left it commented below.

  • It’s almost that, but how did you make two selects, like this, the first p (from the first select) and the second p (from the second select) would refer to the msm object? In addition, the date has q be a condition of ">" (greater than). How to do this using select, if x is a list?

  • Actually there are two selects, in the list I use the P I’m picking(selecting) only the names, is the equivalent of IN of SQL, As for the >, I have a doubt, you need that when you have "match" the name, the date is bigger than the object that gave "match"? I updated here to make the select https://dotnetfiddle.net/grAVrgissue more visible

  • Got it. Yes, the match has to be the name and date of the object that gave match.

  • I understood what you want, it would validate you edit the question and add this information, including Fiddle, I will only be able to stop to see more the night, then it may be that someone else can help you(for now I will keep the answer in case someone comes in check the history, but the night I remove it because it does not answer the question.)

  • @Renangonzales see if this is what you wish (https://dotnetfiddle.net/grAVrg)

  • That’s pretty much it. Only this way, for each operation will be done a different query in the database (I tried to implement it the way you said and added a trace in the database to make sure). And, another problem is that I have to get the top 1000 sorted by ID, for example, and if you do separate query it n will pick in the correct order.

  • Understand, my knowledge of LINQ prevents me from thinking of another way to solve this with Lambda, maybe with SQL I can, would help you in something? if yes, the database is sql-Sever?

  • I have not so much knowledge. But there is no problem, in SQL I managed to do already. Thank you very much for the help. If you can leave the answer there, thank you. Because there is a lot of talk and explanation in it.

  • Blz, I keep it.

Show 13 more comments

0


I managed to solve the problem.

The way a list can be iterated over another, is by using the "Any()" function of the second list, within the condition of the first. Fiddle with the problem solved: https://dotnetfiddle.net/QuXwQZ

TL;DR: Excerpt from the code that solved the problem:

List<Contact> listaResultado = 
contacts
.Where(
    x => 
        operations.Any(
            y => 
                x.OperationName.Equals(y.Name) 
                && x.ContactDate > y.StartDate
        )
).ToList();

Browser other questions tagged

You are not signed in. Login or sign up in order to post.