0

In oracle I can do the following query:

SELECT *
FROM Tabl Tabb
WHERE (tabb.Col1, tabb.Col2) IN ( (1,2), (3,4))

Consider I 've following entity:

public class Tabb
{
   public int Col1 {get; set; }
   public int Col2 {get; set; }
   // other props
}

and criteria class

public class Search
{
   public int Col1 {get; set; }
   public int Col2 {get; set; }
}

I need to write:

public IEnumerable<Tabb> Select(IEnumerable<Search> s)
{
   var queryable = this.context.Tabbs;
   return queryable.Where(\* some *\).ToList();
}

How can I select entities, that search collection contain instance of search that has the same value of Col1 and Col2?

EDIT:

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

It doesn't work (As I expected) - in may case entity2 is not a entity table, it is static collection, so EF throws exception (sth like: cannot find mapping layer to type Search[]);

  • 1
    OK, but it is possible to JOIN entity table to static collection? Whole operation should be done at database side. –  Aug 29 '14 at 07:16
  • @No1_Melman as I expected, join doesn't work. See my edit. –  Aug 29 '14 at 07:44

2 Answers2

0

Just understood the problem better. You want all rows where the columns match, may be this will help:

myDBTable.Where(x => 
     myStaticCollection.Any(y => y.Col2 == x.Col2) && 
     myStaticCollection.Any(y => y.Col1 == x.Col1))
     .ToList()
     .Select(x => new Search { Col1 = x.Col1, Col2 = x.Col2 });

This is saying, I want each row where any Col2 in my static collection matches this database Col2 AND where any Col1 matches this database Col1

this.context.Searches.Join(
     this.context.Tabbs,
     s => s.Col2,
     t => t.Col2,
     (search, tab) => new {
          search,
          tab
     });

This will bring back IEnumerable<'a> containing a search and a tab

This guy is doing something similar LINK

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

Once you have your result then you want to enumerate that to make sure you're hitting the database and getting all your values back. Once they're in memory, then you can project them into objects.

result.ToList().Select(a => new MyEntity { MyProperty = a.Property });
Community
  • 1
  • 1
Callum Linington
  • 14,213
  • 12
  • 75
  • 154
  • Won't it join only by `Col2`? –  Aug 29 '14 at 07:18
  • 1
    You could make a composite key, maybe do a group by – Callum Linington Aug 29 '14 at 07:19
  • Grouping seems to be a better solution –  Aug 29 '14 at 07:20
  • @pwas check my new answer – Callum Linington Aug 29 '14 at 07:21
  • @IlyaIvanov matter of opinion, I prefer LINQ functions to be honest, query syntax confuses me :) – Callum Linington Aug 29 '14 at 07:22
  • @No1_Melman, thanks I will check that. But I've a doubt - I won't to do a join with two entity tables but entity table with static collection. I hope EF will swallow it. –  Aug 29 '14 at 07:23
  • @No1_Melman It doesn't want to compile, I need to specify generic arugments explicity, what is not possible because of anynomus type in key join expression. –  Aug 29 '14 at 07:38
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60230/discussion-between-no1-melman-and-pwas). – Callum Linington Aug 29 '14 at 12:36
  • @No1_Melman I see, buy it is not what I want. Consider: Search1: { col1 = 1, col2 = 2 } and Search2: { col1 = 2, col2 = 3}. In database: entity1: { col1 = 1, col2 = 3 }. You first solution will return entity, but it shouldn't. –  Aug 29 '14 at 13:18
  • @pwas so just project it then, like i show at the bottom of my post – Callum Linington Aug 29 '14 at 13:32
  • @No1_Melman what projection will change in this case? Result will contain invalid entities. –  Aug 29 '14 at 13:47
0

There's a few ways, which all have pros and cons, and are sometimes a little bit tricky...

Solution 1

You enumerate the ef part first (of course, depending on the size of your data, this might be a very bad idea)

Solution 2

You concatenate your fields with an element you're sure (hum) you won't find in your fields, and use a Contains on concatenated EF data.

var joinedCollection =entity2.Select(m => m.field1 + "~" + m.field2);

var result = entity.Where(m => joinedCollection.Contains(m.field1 + "~" + m.field2));

of course, this would be a little bit more complicated if field1 and field2 are not string, you'll have to use something like that

SqlFunctions.StringConvert((double)m.field1) + "~" + //etc.

Solution 3

you do this in two step, assuming you will have "not too much result" with a partial match (on only one field)

var field1Collection = joinedCollection.Select(m => m.field1);

var result = entity.Where(m => joinedCollection.Contains(m.field1)).ToList();

then you make the "complete join" on the two enumerated lists...

Solution 4

use a stored procedure / generated raw sql...

Raphaël Althaus
  • 59,727
  • 6
  • 96
  • 122
  • Unfortunately, the table contains thousand of records, and result also may contain lots of items. The only solution suitable for me is no 2. But, won't that "little hack" cause some perfromance problem? Especially, I've index on both column... When using that solution - index loose ability to increase performance. –  Aug 29 '14 at 09:56
  • @pwas yes, it will be bad for indexes. But may be worth a try. One (not so far) way could be to create a computed column (if you're inSql Server) which might be the result of the concatenation and could (maybe) be indexed... But is it worth it ? Hard to say. – Raphaël Althaus Aug 29 '14 at 09:59
  • Hmm, I'd like to avoid stored procedures, but there in this case this is the only reasonable solution, this. Question: will EF accept table parameter (will generate proper method) or ADO.NET is the only way... –  Aug 29 '14 at 10:02
  • @pwas think you can, I found some answers on SO about this... Or see for example this : http://code.msdn.microsoft.com/Stored-Procedure-with-6c194514 (might be outdated ?) – Raphaël Althaus Aug 29 '14 at 12:22