EF4 code-first: defining object relationships, foreign keys

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 :-)

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 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?

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.

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.

But is it considered good practice to explicitly specify such properties holding FKs, in addition to 'foreign objects' themselves?

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.

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:

modelBuilder.Entity().MapHierarchy(a => new
{
    a.Id, 
    Owner_Id = a.Owner.Id
}).ToTable("Account");

modelBuilder.Entity().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?

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.

Thank you in advance for your time!

17
задан Morteza Manavi 26 November 2010 в 04:58
поделиться