在开始之前,请注意我已经简化了我尝试做的事情的数据结构,而在现实世界中,它并不像您想象的那样糟糕。或者也许是。无论如何,我无法改变数据结构的方式,因此我不会寻找有关如何更好地构建数据的建议。我只是希望看看我是否可以按照我在实体框架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表中提取数据时总是包含额外的过滤器吗?
答案 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类只是实现存根。