EF Include始终为第一个导航属性生成INNER JOIN

时间:2012-06-15 17:02:30

标签: c# asp.net .net linq entity-framework

我正在使用Code First方法并具有以下模型:

public class Person
{
    public int ID {get; set;}
    public string Name {get; set;}

    public int CurrentStationID {get; set;}
    public virtual Station CurrentStation {get; set;}

    public int CurrentTransportationID {get; set;}
    public virtual Transportation CurrentTransporation {get; set;}
}

我控制器中的以下代码:

Models.Person model = myDBContext.Persons
                        .Include("CurrentStation")
                        .Include("CurrentTransportation")
                        .Where(p => p.ID == 1)
                        .FirstOrDefault();
即使在数据库表“人员”中存在(1,“Testname”,0,0)的行,

“model”也将为NULL。

上面使用[...] INNER JOIN stations AS [...] LEFT JOIN transportations [...]生成一个SQL语句。对于我的所有模型,它始终为第一个导航属性执行INNER JOIN,无论基础表/类型是什么或我指定它们的顺序,它始终是第一个Include()。

想要一个INNER JOIN,但是想要一个LEFT JOIN,因为“CurrentStation”不需要在数据库中。

为什么EF会这样做?我不明白,但我想明白。我没有在任何属性上指定[Required] -attribute,但它的行为就像我一样。

不幸的是,没有[Optional] -attribute并且通过OnModelCreate-override执行“HasOptional()”对我来说不是一个选项。

2 个答案:

答案 0 :(得分:6)

如果我没有弄错,为了允许属性是可选的或在数据库意义上,可以为空,你必须使属性可以为空。因此,对于CurrentStationId属性,您可以尝试按如下方式声明:

 public int? CurrentStationId {get;set;}

<强>更新post可能对您的情况有所帮助。

答案 1 :(得分:2)

首先应该弄错的是数据库的设计。如果您可以CurrentStationId = 0并且同时Station没有Id = 0,则表示您的数据库不使用参照完整性。

参照完整性是使用EF的先决条件。如果你想在实体之间建立关系,请确保数据库中存在这样的关系,并强制执行引用约束,否则我相信你还会扼杀许多其他意想不到的行为。

如果您可以让没有Station的人,唯一正确的方法是让CurrentStationId列和属性可以为空。因为EF认为在数据库中强制执行约束(并且您无法将其关闭),因此它可以使用INNER JOIN,并且在不使FK可为空的情况下无法更改它。如果你不能在数据库中改变它,不要在EF中映射关系 - 或者最好不要使用EF。

如果您可以控制数据库,而且如果您以这种方式设计它,则应停止编码并返回白板以考虑设计并改进它以遵循数据库设计最佳实践。这将为您节省许多将来可能遇到的问题。