我可以在Entity Framework 6中的关系中的属性上定义过滤器吗?

时间:2015-05-15 03:25:53

标签: c# entity-framework

在开始之前,请注意我已经简化了我尝试做的事情的数据结构,而在现实世界中,它并不像您想象的那样糟糕。或者也许是。无论如何,我无法改变数据结构的方式,因此我不会寻找有关如何更好地构建数据的建议。我只是希望看看我是否可以按照我在实体框架6中提出的方式做。

考虑我有以下表格:

人:

ID    FirstName    LastName
1     John         Smith
2     Jane         Doe

作业:

ID    Name
1     Developer

ExtendedData:

ID    TableName    RowID    FieldName      FieldValue
1     Person       1        MiddleInitial  A
2     Person       1        Gender         M
3     Person       2        MiddleInitial  B
4     Person       2        Gender         F
5     Job          1        Description    Develop Stuff

此ExtendedData表的目的是允许在没有数据列时存储其他数据。 例如,这里" MiddleInitial"不是Person表中的列,但是在ExtendedData表中我们可以添加一行来存储该数据。

在我的"人"我可以添加以下代码来添加ExtendedData属性:

public virtual ICollection<ExtendedData> ExtendedData { get; set; }

然后我可以用以下方法在Entity Framework中创建一个关系:

modelBuilder.Entity<Person>()
    .HasMany(e => e.ExtendedData)
    .WithRequired(e => e.Person)
    .HasForeignKey(e => e.RowID);

我所关心的是,如果我打电话......

john = Persons.Where(a => a.ID == 1);
john.ExtendedData...

...我将返回RowID = 1的所有扩展数据行,包括&#34; Job&#34;表。 显然,我可以做点像......

john.ExtendedData.Where(a => a.TableName == "Person")...

...但这有点危险,因为如果我(或其他一些开发人员)忘记在代码中指定额外的过滤器呢?

我尝试过这样的事情......

modelBuilder.Entity<Person>()
    .HasMany(e => (ICollection<ExtendedData>))e.ExtendedData.Where(a => a.TableName == "Person"))
    .WithRequired(e => e.Person)
    .HasForeignKey(e => e.RowID);

...但在运行时收到错误说明......

  

表达式&#39; e =&gt;转换(e.ExtendedData.Where(a =&gt;(a.TableName ==   &#34;人&#34;)))&#39;不是有效的属性表达式。表达应该   表示属性:C#:&#39; t =&gt; t.MyProperty&#39; VB.Net:&#39;功能(t)   t.MyProperty&#39;

我对它的感觉是它要我指定一个属性来自&#34; e&#34;而不是试图做任何进一步的巫术。

我可以在任何地方修改Entity Framework模型,以便在我调用时 person.ExtendedData它只会返回给我的ExtendedData记录,其中TableName =&#34; Person&#34;?或者我必须记得在尝试从ExtendedData表中提取数据时总是包含额外的过滤器吗?

1 个答案:

答案 0 :(得分:0)

这里你真正想要的是Table Per Hierarchy。为表定义基本实体,然后为每个变体定义一个继承的实体,并自定义鉴别器。

Public abstract class ExtendedData
{
    public int Id {get;set;}
    public string FieldName {get;set;}
    public string FieldValue {get;set;}
}

public class ExtendedPersonData : ExtendedData
{}

public class ExtendedJobData : ExtendedData
{}

public class Person
{
    ....
    public virtual ICollection<ExtendedPersonData> ExtendedData {get;set}
}

public class Job
{
    ....
    public virtual ICollection<ExtendedJobData> ExtendedData {get;set;}
}

public class Context : DbContext
{
    ....
    public DbSet<ExtendedData> ExtendedData {get;set;}
} 

modelBuilder.Entity<ExtendedData>()
    .Map<ExtendedPersonData>(m => m.Requires("TableName").HasValue("Person"))
    .Map<ExtendedJobData>(m => m.Requires("TableName").HasValue("Job"));

使用继承的类,您现在可以对表数据进行非多态查询,即

IQueryable<ExtendedPersonData> query = from e in context.ExtendedData
                                                .OfType<ExtendedPersonData>()
                                       select e;

这将生成一个SQL查询,该查询仅返回鉴别器列匹配的记录(在这种情况下为"TableName" == "Person")。由于在实体上定义的集合类型,返回Person并查询它的ExtendedData会自动创建非多态查询。

请注意,在这种情况下,您可以混合每个变体唯一的共享列和列。任何特定于唯一变体的列都将在表中自动变为可为空,并且只能由提供它的实体填充。但是,在您的情况下,您没有唯一列,因此Inherited类只是实现存根。

http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph