Using .NET 4.5.1 and Entity Framework 6.0.2 , I've got something like the entities and query below.
Basically I am selecting a new
entity and mashing the Distance
into it, when I'd rather query a Person
and have Distance
embedded in that person's Location
entity.
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
[...]
public virtual ICollection<PersonLocation> PersonLocations { get; private set;}
}
public class Location
{
public int Id { get; set; }
public DbGeography Geocode { get; set; }
// ... I want calculated Distance right here
}
public class PersonLocation
{
public int PersonId { get; set; }
public int LocationId { get; set; }
public bool AcceptingNewClients { get; set; }
public Hours Hours { get; set; }
[...]
public virtual Person Person { get; private set; }
public virtual Location Location { get; private set; }
}
Currently I have a query like this, where _geo
is a DbGeography
set to the desired search location and radius
is an int = 15
:
IQueryable<PersonWithDistance> results =
from pl in db.PersonLocations
let distance = pl.Location.Geocode.Distance(_geo)
where pl.Location.Geocode.IsEmpty == false
where distance <= radius * 1609.344
orderby distance
select new { Person = pl.Person, Distance = Math.Round((double)(distance / 1609.344), 1) };
What I'd like instead is to have Distance
added to each Location
entity and just select the Person
entity in the query.
Is there a way to do this? Should I be going a different route altogether?
What I ended up doing was this:
public class Location
{
public int Id { get; set; }
public DbGeography Geocode { get; set; }
public double? Distance { get; set; }
}
In the DbContext setup, so that EF ignores the column as it relates to the database:
Ignore(x => x.Distance);
The search query becomes:
var results = (from pl in db.PersonLocations
let distance = pl.Location.Geocode.Distance(_geo)
where pl.Location.Geocode.IsEmpty == false
where distance <= radius * 1609.344
select pl.Person).Distinct();
And finally:
var personsWithDistance = results.ToList();
foreach (Person p in personsWithDistance)
{
var pls = p.PersonLocations;
foreach (PersonLocation pl in pls)
{
if (pl.Location.Geocode != null)
pl.Location.Distance = Math.Round((double)(pl.Location.Geocode.Distance(_geo) / 1609.344), 1);
else
pl.Location.Distance = null;
}
}
// order by distance
personsWithDistance = personsWithDistance.OrderBy(r => r.PersonLocations.FirstOrDefault().Location.Distance).ToList();
return personsWithDistance;
Essentially I created a fake column/property in the Location
entity and told the DbContext to ignore it. I query for the resultset I want and then manually update the property and return the results.
It doesn't feel right somehow, but it works.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.