< RANT_MODE >
EF code-first approach is meant to save lots of time but for the time being I've only seen toy examples and spent hours trying to understand how I can make it generate the db I want. But still hoping that Eureka moment :-)
EF代码优先方法意味着节省大量时间,但暂时我只看过玩具示例,花了好几个小时试图了解如何让它生成我想要的数据库。但仍然希望尤里卡时刻:-)
< RANT_MODE />
On to the questions!
关于问题!
Virtual vs. concrete properties
I'm trying to understand how EF maps and retrieves object relationships. When should I mark a property as virtual
and when not? (As in public Person Owner { get; set; }
vs. public virtual Person Owner { get; set; }
.) In the dozens of examples of code-first I've seen they seem to use these interchangably, without much in terms of explanation. What I do know is that navigation properties (public virtual ICollection<Person> Owners { get; set; }
) need to be virtual
in order to make lazy loading possible (correct..?), but how does that apply in the world of non-collections?
我试图了解EF如何映射和检索对象关系。我应该何时将属性标记为虚拟属性,何时不标记? (如公共人物所有者{get; set;}与公共虚拟人物所有者{get; set;}。)在代码优先的几十个例子中,我看到他们似乎可以互换地使用这些,但没有多少解释。我所知道的是导航属性(公共虚拟ICollection
Object relationships and foreign keys
I wasn't able to find any information on whether I should include a foreign key field (public int OwnerId { get; set; }
) in addition to the 'main' property I'm interested in (public Person Owner { get; set; }
). I tried not to, and EF kindly auto-added an int column named Owner_Id
in my table, seemingly understanding what I meant to achieve.
除了我感兴趣的'main'属性之外,我无法找到关于是否应该包含外键字段(public int OwnerId {get; set;})的任何信息(public Person Owner {get; set ;})。我尽力不去,EF在我的表中自动添加了一个名为Owner_Id的int列,似乎理解了我的意图。
In Conventions for Code First (section 'Foreign Keys') the EF Team mention that "it is common to include a foreign key property on the dependent end of a relationship", and that "Code First will now infer that any property named '' (i.e. OwnerId) [...] with the same data type as the primary key, represents a foreign key for the relationship". Ie. if I have both EF will know they're related.
在Code First的约定(“外键”部分)中,EF团队提到“在关系的依赖端包含外键属性是很常见的”,并且“Code First现在将推断任何名为''的属性(即OwnerId)[...]与主键具有相同的数据类型,表示关系的外键“。 IE浏览器。如果我有两个EF会知道他们是相关的。
But is it considered good practice to explicitly specify such properties holding FKs, in addition to 'foreign objects' themselves?
但是,除了“异物”本身之外,明确指定持有FK的此类属性是否被视为良好做法?
Foreign objects, foreign keys - continued
As I mentioned above, even if I only have public Person Owner { get; set; }
in my object (say Event
), the table Events
will feature an Owner_Id
column automagically added by EF. What's more, upon retrieval I will have access to properties of Owner
.
正如我上面提到的,即使我只有公共人物所有者{get;组;在我的对象(比如Event)中,表Event将包含由EF自动添加的Owner_Id列。更重要的是,在检索后,我将可以访问所有者的属性。
However, consider the following scenario. I've got two classes:
但是,请考虑以下方案。我有两节课:
public class Account
{
public int Id { get; set; }
public Person Owner { get; set; }
}
public class OpenIdAccount : Account
{
public string Identifier { get; set; }
}
I want them to be TPT-related. This means manual mapping:
我希望他们与TPT有关。这意味着手动映射:
modelBuilder.Entity<Account>().MapHierarchy(a => new
{
a.Id,
Owner_Id = a.Owner.Id
}).ToTable("Account");
modelBuilder.Entity<OpenIdAccount>().MapHierarchy(a => new
{
a.Id,
a.Identifier
}).ToTable("OpenIdAccount");
As you may notice, I tried to recreate what EF does with my Owner_Id
column. Yet upon retrieval, myAccountInstanceFromDb.Owner
is null. Why is that? How do I tell EF that it should do its magic and populate my Owner
property?
您可能已经注意到,我尝试使用Owner_Id列重新创建EF。但是在检索时,myAccountInstanceFromDb.Owner为null。这是为什么?我怎么告诉EF它应该发挥它的魔力并填充我的所有者属性?
Pointers, pointers
I will be most grateful if you could clarify the above - got to the point of really wishing to know the answers, but being unable to read yet another article that merely showcases another toy example of how easy it is to play with EF. That said, if you do have an in-depth up-to-date reference on EF's brains, please do post links too.
如果你能澄清上述内容,我将非常感激 - 到了真正希望知道答案的地步,但又无法阅读另一篇仅仅展示另一个玩具的例子,说明与EF一起玩是多么容易。也就是说,如果你对EF的大脑有一个深入的最新参考,请发布链接。
Thank you in advance for your time!
提前感谢您的时间!
2 个解决方案
#1
9
Virtual vs. Final properties:
This has really nothing to do with code first, it's the topic of EF and POCOs: When you have POCOs you lose a bunch of EF supports for your navigation properties and you can opt in to them by making them virtual. This lets EF to make a proxy at runtime and give you the support by overriding the nav properties in that proxy class. Those supports are Change Notification, Relationship Fixup and Lazy Loading.
这与代码首先无关,它是EF和POCO的主题:当您拥有POCO时,您会失去对导航属性的大量EF支持,您可以通过将它们设置为虚拟来选择加入它们。这使EF可以在运行时创建代理,并通过覆盖该代理类中的导航属性来为您提供支持。这些支持是Change Notification,Relationship Fixup和Lazy Loading。
Lazy Loading works the same for Collection and non Collection type navigation properties. Also it's considered to be a good practice to always mark your navigation properties as virtual.
延迟加载对Collection和非Collection类型导航属性的工作方式相同。此外,始终将导航属性标记为虚拟也是一种很好的做法。
Foreign Key Association or Independent Associations
EF3.5 does not support FKs in the associations and makes them hidden (a.k.a Independent Associations). EF4 starts to support FKs in the associations (a.k.a Foreign Key Association). Depend on which one you like, you can explicitly include or not include FK properties, but it's definitely a good practice to explicitly specify FK properties, in addition to navigation properties since it gives you ultimate flexibility to work with your objects.
EF3.5不支持关联中的FK并使它们隐藏(a.k.a独立关联)。 EF4开始支持协会中的FK(a.k.a外键协会)。取决于您喜欢哪一个,您可以明确包含或不包含FK属性,但除了导航属性之外,明确指定FK属性绝对是一个好习惯,因为它为您提供了使用对象的最大灵活性。
Upon retrieval, myAccountInstanceFromDb.Owner is null. Why is that? How do I tell EF that it should do its magic and populate my Owner property?
检索后,myAccountInstanceFromDb.Owner为空。这是为什么?我怎么告诉EF它应该发挥它的魔力并填充我的所有者属性?
Of course, you didn't marked it as virtual so Lazy Loading is not supported yet you did not explicitly eager load or defer load it as well. To resolve that either use virtual keyword and let EF lazy load it for you or use Include method to eager load it at the time the whole object is materialized.
当然,您没有将其标记为虚拟,因此不支持延迟加载,但您没有明确地急切加载或延迟加载它。要解决这个问题,要么使用虚拟关键字,让EF懒惰加载它,或者使用Include方法在整个对象实现时急切加载它。
Scalar properties vs. Navigation properties
Scalar properties are properties whose values are literally contained in the entity and correspond with the table columns (e.g. Account.Id).
Navigation properties are merely pointers to the related entities. For example the Account entity has an Owner property that will enable the application to navigate from an Account to the Owner that owns that Account.
So, back to your question, all you need to do is to specify a navigation property as virtual Person Owner
and optionally specify a FK property as int OwnerId
and you are good to go.
标量属性是其值实际上包含在实体中并与表列对应的属性(例如Account.Id)。导航属性仅是指向相关实体的指针。例如,Account实体具有Owner属性,该属性将使应用程序能够从Account导航到拥有该Account的所有者。所以,回到你的问题,你需要做的就是将导航属性指定为虚拟人物所有者,并可选择将FK属性指定为int OwnerId,你就可以了。
#2
0
marking a property virtual makes the related objects to be lazy invoked
标记属性virtual会使相关对象被惰性调用
you need not add a foreign key field public Person Owner { get; set; } will add a foreign key mapping
你不需要添加外键字段public Person Owner {get;组;将添加外键映射
#1
9
Virtual vs. Final properties:
This has really nothing to do with code first, it's the topic of EF and POCOs: When you have POCOs you lose a bunch of EF supports for your navigation properties and you can opt in to them by making them virtual. This lets EF to make a proxy at runtime and give you the support by overriding the nav properties in that proxy class. Those supports are Change Notification, Relationship Fixup and Lazy Loading.
这与代码首先无关,它是EF和POCO的主题:当您拥有POCO时,您会失去对导航属性的大量EF支持,您可以通过将它们设置为虚拟来选择加入它们。这使EF可以在运行时创建代理,并通过覆盖该代理类中的导航属性来为您提供支持。这些支持是Change Notification,Relationship Fixup和Lazy Loading。
Lazy Loading works the same for Collection and non Collection type navigation properties. Also it's considered to be a good practice to always mark your navigation properties as virtual.
延迟加载对Collection和非Collection类型导航属性的工作方式相同。此外,始终将导航属性标记为虚拟也是一种很好的做法。
Foreign Key Association or Independent Associations
EF3.5 does not support FKs in the associations and makes them hidden (a.k.a Independent Associations). EF4 starts to support FKs in the associations (a.k.a Foreign Key Association). Depend on which one you like, you can explicitly include or not include FK properties, but it's definitely a good practice to explicitly specify FK properties, in addition to navigation properties since it gives you ultimate flexibility to work with your objects.
EF3.5不支持关联中的FK并使它们隐藏(a.k.a独立关联)。 EF4开始支持协会中的FK(a.k.a外键协会)。取决于您喜欢哪一个,您可以明确包含或不包含FK属性,但除了导航属性之外,明确指定FK属性绝对是一个好习惯,因为它为您提供了使用对象的最大灵活性。
Upon retrieval, myAccountInstanceFromDb.Owner is null. Why is that? How do I tell EF that it should do its magic and populate my Owner property?
检索后,myAccountInstanceFromDb.Owner为空。这是为什么?我怎么告诉EF它应该发挥它的魔力并填充我的所有者属性?
Of course, you didn't marked it as virtual so Lazy Loading is not supported yet you did not explicitly eager load or defer load it as well. To resolve that either use virtual keyword and let EF lazy load it for you or use Include method to eager load it at the time the whole object is materialized.
当然,您没有将其标记为虚拟,因此不支持延迟加载,但您没有明确地急切加载或延迟加载它。要解决这个问题,要么使用虚拟关键字,让EF懒惰加载它,或者使用Include方法在整个对象实现时急切加载它。
Scalar properties vs. Navigation properties
Scalar properties are properties whose values are literally contained in the entity and correspond with the table columns (e.g. Account.Id).
Navigation properties are merely pointers to the related entities. For example the Account entity has an Owner property that will enable the application to navigate from an Account to the Owner that owns that Account.
So, back to your question, all you need to do is to specify a navigation property as virtual Person Owner
and optionally specify a FK property as int OwnerId
and you are good to go.
标量属性是其值实际上包含在实体中并与表列对应的属性(例如Account.Id)。导航属性仅是指向相关实体的指针。例如,Account实体具有Owner属性,该属性将使应用程序能够从Account导航到拥有该Account的所有者。所以,回到你的问题,你需要做的就是将导航属性指定为虚拟人物所有者,并可选择将FK属性指定为int OwnerId,你就可以了。
#2
0
marking a property virtual makes the related objects to be lazy invoked
标记属性virtual会使相关对象被惰性调用
you need not add a foreign key field public Person Owner { get; set; } will add a foreign key mapping
你不需要添加外键字段public Person Owner {get;组;将添加外键映射