计算和返回EF 6 / LINQ到Entities / DbGeography的距离?

时间:2014-02-24 16:20:59

标签: c# linq entity-framework sql-server-2012

使用 .NET 4.5.1 Entity Framework 6.0.2 ,我有类似下面的实体和查询。

基本上我选择new实体并将Distance混入其中,当我宁愿查询Person并将Distance嵌入该人Location时1}}实体。

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; }
}

目前我有这样的查询,其中_geo是设置为所需搜索位置的DbGeography,而radiusint = 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) };

我想要的是将Distance添加到每个Location实体,只需在查询中选择Person实体。

有办法做到这一点吗?我应该完全走另一条路吗?

1 个答案:

答案 0 :(得分:0)

我最终做的是:

public class Location
{
    public int Id { get; set; }
    public DbGeography Geocode { get; set; }

    public double? Distance { get; set; }
}

在DbContext设置中,以便EF忽略与数据库相关的列:

Ignore(x => x.Distance);

搜索查询变为:

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();

最后:

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;

基本上我在Location实体中创建了一个假的列/属性,并告诉DbContext忽略它。我查询我想要的结果集,然后手动更新属性并返回结果。

不知何故感觉不对,但它确实有效。