I\'m trying to query data of the form with LINQ-to-EF:
class Location {
string Country;
string City;
string Address;
…
}
by
If you're not going to need a lot of key combinations, you can simply add a LocationKey
property to your data. To avoid wasting a lot of storage, maybe make it the hash code of the combined properties.
Then query on will simply have a condition on LocationKey
. Finally, in the client side filter the results to drop entities that had the same hash but not the same location.
It would look something like:
class Location
{
private string country;
public string Country
{
get { return country; }
set { country = value; UpdateLocationKey(); }
}
private string city;
public string City
{
get { return city; }
set { city = value; UpdateLocationKey(); }
}
private string address;
public string Address
{
get { return address; }
set { address = value; UpdateLocationKey(); }
}
private void UpdateLocationKey()
{
LocationKey = Country.GetHashCode() ^ City.GetHashCode() ^ Address.GetHashCode();
}
int LocationKey;
…
}
Then simply query on the LocationKey property.
Not ideal, but it should work.
var keys = new[] {
new {Country=…, City=…, Address=…},
…
}
var result = from loc in Location
where keys.Any(k=>k.Country == loc.Country
&& k.City == loc.City
&& k.Address == loc.Address)
select loc
Give this a try.
Have you tried just using the Tuple class?
var keys = new[] {
Tuple.Create("Country", "City", "Address"),
…
}
var result = from loc in Location
where keys.Contains(Tuple.Create(loc.Country, loc.City, loc.Address))
How about:
var result = locations.Where(l => keys.Any(k =>
k.Country == l.Country &&
k.City == l.City &&
k.Address == l.Address));
UPDATE
Unfortunately EF throws NotSupportedException on that, which disqualifies this answer if you need the query to run on DB side.
UPDATE 2
Tried all kinds of joins using custom classes and Tuples - neither works. What data volumes are we talking about? If it's nothing too big, you could either process it client-side (convenient) or use unions (if not faster, at least less data is transmitted).
i think the proper way to do it is
var result = from loc in Location
where loc.Country = _country
where loc.City = _city
where loc.Address = _address
select loc
It looks unoptimized but the query provider will go out and do the optimization when it transforms the query to sql. When using tuples or other classes, the query provider doesnt know how to transform them into sql and that what causes the NotSupportedException
-edit-
If you have multiple key tuples i think you have to loop through them all and do the above query for each one. again, that might seem underoptimized, but the query for retriving all the locations in a single query would probably end up beeing quite long:
select * from locations
where (locations.Country = @country1 and locations.City = @city1, locations.Adress = @adress1)
or (locations.Country = @country2 and locations.City = @city2, locations.Adress = @adress2)
or ...
The fastest way of doing it is probably to do the simple queries, but send them as a single sql script and use multiple result sets for actually getting each value. Im not sure you can get EF to do that though.
You can project a string concat key and match on the projection. However, do note that you will not be able to use any indexes built on the columns and will be doing a string match which could prove to be slow.
var stringKeys = keys
.Select(l => $"{l.Country}-{l.City}-{l.Address}")
.ToList();
var result = locations
.Select(l => new
{
Key = l.Country + "-" + l.City + "-" + l.Address)
}
.Where(l => stringKeys.Contains(l.Key))
.ToList();