如何使用EF Code First表示选项计算列?

时间:2011-03-14 17:46:52

标签: linq entity-framework entity-framework-4 code-first ef-code-first

我有一个情况,我有一个条目表,我将查询,但在某些情况下,我会有更多的信息。

例如,如果我有一个people的表,我希望能够按名称进行搜索,但我也希望存储一些坐标并根据它们的位置进行搜索,但也要在对象模型。因此,例如,假设我的people表看起来像这样:

PersonId int
Name nvarchar(100)
Address nvarchar(100)
Latitude float(10,6)
Longitude float(10,6)

实体类的定义如下:

public class Person
{
     public int PersonId { get; set; }
     public sting Name { get; set; }
     public float Latitude { get; set; }
     public float Longitude { get; set; }
}

然后我可以通过名字轻松找到一个人:

var people = from p in myDb.People where p.Name.Contains("joe");

现在,我已经创建了一个名为CalculateDistance的用户定义函数来处理这个距离计算。所以我的SQL看起来像这样:

String sql = "SELECT *, dbo.CalculateDistance(" + location.X + ", " + location.Y + ", Latitude, Longitude) AS Distance FROM people ORDER BY Distance

我如何在代码中表示这一点?我试过在课堂上添加这样的属性:

public virtual float Distance { get; set; }

但是名称查询失败,因为没有Distance列。我也试过扩展Person类:

public class PersonWithDistance: Person {
    public float Distance { get; set; }
}

但这导致了映射生成方式的更多问题。

实现这样的事情的正确方法是什么?我是否必须为距离查询的结果创建一个完全独立的单独类?

2 个答案:

答案 0 :(得分:4)

这不是很好的设计。您应该将距离作为Person或某个帮助程序类的方法,并在应用程序中计算距离而不是数据库中的距离。它还需要将位置转移给该人。

无论如何,如果要添加一些未映射到数据库中的列的属性,则必须将其从映射中排除。这可以通过属性:

完成
[NotMapped]
public float Distance { get; set; }

或通过流利的API:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Person>().Ignore(p => p.Distance);
}

答案 1 :(得分:1)

我最后创建了一个PersonResult类,其中包含IdDistance和Person对象,如下所示:

public class PersonResult {
     [Key]
     public int PersonId { get; set; }
     public double Distance { get; set; }
     public virtual Person Person { get; set; }
}

我从这样的存储过程填充它:

var results = myDb.PersonResults.SqlQuery("EXEC PeopleByDistance " + lat + ", " + lng);

循环遍历结果以填充Person对象:

foreach (PersonResultresult in results)
{
    result.Person = myDb.People.Where(p => p.PersonId == result.PersonId).FirstOrDefault();
}

这似乎运作良好。虽然我不确定这是处理它的最好方法。