Why is there duplication of references in code-first EntityFramework? - c#

In learning the code-first EntityFramework methodology, I don't understand why you need "duplicate" references between two data sets, i.e. a Navigation Property as well as an explicitly defined foreign key.
For example, an "Enrollment" has a one-to-one relationship with a "Course" and a "Student". In the student's model class, you define a navigation property like so:
public virtual ICollection<Enrollment> Enrollments { get; set; }
This will create a column for foreign keys to Student in the Enrollments table if you do a migration.
But in the "Enrollment" class, you also have a property representing the Student's foreign key like so:
public int StudentID { get; set; }
So my question is: what is the purpose of defining this foreign-key relationship on both ends? I have seen it done where only the Navigation Property is defined on one end, and also where the relationship is only defined on the other end. What is the reason for both?

The navigation property allows you to access the collection of referenced entities when you query the entity.
The single ID property is the reference to the column that actually holds the value of the foreign key reference.

Related

Entity Framework Relationship Matching - No Foreign Keys In DB

I've gone through the Entity Framework code-first tutorials and I hate to say but I'm at a loss for how it works. Everything works but I want to know how because everything I know about basic database design tells me it shouldn't. I feel like I'm missing a critical link with how it's creating foreign keys and hope someone can explain it.
I initially copied and pasted a bunch of code-first designs of a simple Parent class with multiple child types. In my child types I had a reference to the virtual Parent and a ParentID reference. I noticed in the database that the value of ParentID was 0 for every single child of type A and B.
However, when loading the data in code and debugging/displaying, entity relationships were correctly maintained.
The code looks like (class names were changed to remove context of what it is):
public class Parent{
public int? ParentID {get;set;}
public virtual ChildA ChildA {get;set;}
public virtual ChildB ChildB {get;set;}
}
public class ChildA{
[Key,ForeignKey(Parent)]
public int ChildAID {get;set;}
public string Field {get;set;}
//public int ParentID {get;set;}
[ForeignKey("ParentID")]
public virtual Parent Parent {get;set;}
}
public class ChildB{
[Key,ForeignKey(Parent)]
public int ChildBID {get;set;}
public string Field {get;set;}
//public int ParentID {get;set;}
[ForeignKey("ParentID")]
public virtual Parent Parent {get;set;}
}
I commented out the ParentID to show explicitly what I was talking about. To test this out, I deleted the column in the database and yet the relationships still work correctly. There are only three tables that relate to this in the database (Parent, ChildA, and ChildB). There aren't any foreign keys, and the parent table doesn't reference the children tables and the children tables don't reference the parent table. When I load them from the DBContext, the mappings correctly load them as I saved them.
What am I missing here? Something somewhere is keeping track of this mapping but I can't tell where. And the fact that it isn't stored as a really basic foreign key in the database concerns me about performance.
What do you mean by There aren't any foreign keys, and the parent table doesn't reference the children tables and the children tables don't reference the parent table. ?
I think you were missing to notice that there are relationship between them.
It's called one to zero-or-one relationship.
Your question is a bit baffling because Entity Framework does store relationships as "really basic foreign keys", so I can't see how you've come to that conclusion.
Commenting out the ParentID to show what your talking about doesn't help much because it should actually have had no effect. That is because when you add the [ForeignKey("ParentID")] attribute to the Parent property, you are telling Entity Framework to put a foreign key in the database named "ParentID" to model the Parent relationship.
You don't need the ParentID integer property in your Entity, but it is usually easier to include foreign keys, and most examples show this.
Now, if you do include ParentID, then you don't need the [ForeignKey("ParentID")] attribute on the Parent property because EF will assume that ParentID is the foreign key for the Parent navigation property because you have followed a standard naming convention.
Also you could try this - remove both the ParentID and the [ForeignKey("ParentID"] attribute and update the database. Now you should find that EF has added a foreign key named "Parent_Id". So foreign keys used always!
The [Key,ForeignKey(Parent)] attribute on your keys looks wrong. The ID isn't a navigation property so you don't need to specify a foreign key for it, so I'm not sure what that is doing (actually, on second thoughts, this may be your problem, I think this is specifying a one to one). That Key attribute is also unnecessary because again you have followed a naming convention.
So in summary, get shot of all your attributes and follow the naming conventions until you need to do something tricky!

Entity framework navigation properties naming convention

I have two tables named as Profile and ProfileHistory.
Each record in ProfileHistory has to belong to a profile in Profile table, so there is a foreign key relation between two tables. Besides, in ProfileHistory table, there is a column named as ManagerId which also relates to Profile table with foreign key relation.
Profile table structure
Id int primary key
....
....
ProfileHistory table structure
Id int primary key
ProfileId int foreign key to Profile table
ManagerId int foreign key to Profile table
....
My question is:
Since currently I only know this, I am creating my entity model from database.
Model and therefore entity classes are created with navigation properties in
ProfileHistory entity like following:
public virtual Profile Profile { get; set; }
public virtual Profile Profile1 { get; set; }
It is so confusing. Because it is not clear which navigation property for which relation.
Even it is worse if I have more relations between two tables. navigation property names are becoming Profile, Profile1, Profile2, etc.
I was expecting to have the name of the navigation properties related with its foreign key relations.
How can I make my navigation property names something that related to its foreign key relation, in my case "from Profile1 to ProfileManager" ?
Thank in advance for your kind helps.
Muharrem
You can always rename the properties in model diagram. The name can be found in Properties window when you click on a navigation property.
I haven't tested it, but you can map a property to a column using an attribute:
[Column(“BlogDescription", TypeName="ntext")]
public virtual Profile Profile { get; set; }
[Column("Profile1", TypeName="int")]
public virtual Profile ProfileManager { get; set; }
Change the type and the name of the column as it is in the database.
The way I usually solve this is to add properties through partial classes that better represent what I'm after. This way if I need to delete the entity from the diagram and re-add it, I don't lose any renamed columns from the model.
The downside to this is that you need to remember that you cannot use them in Queries because EF won't know how to translate it into a SQL query. But if you've already got your Profile object, it's a lot easier to access myProfile.Manager than myProfile.Profile1.
So, for example, if EF created this for you:
public partial class ProfileHistory
{
public virtual Profile Profile { get; set; }
public virtual Profile Profile1 { get; set; }
}
I would end up creating a partial class like this to re-map the columns:
public partial class ProfileHistory
{
public Profile Manager
{
get
{
return this.Profile1;
}
set
{
this.Profile1 = value;
}
}
}
I did face the same problem some time ago. Well, it is even bigger then just confusing names. If you have navigation properties to another table, like Profile, Profile1, Profile2, next you delete/edit the corresponding foreign keys you may end up having those mixed. And if you used EntitySQL to query data you'll end up having bugs because of incorrect data retrieved/wrong table join conditions...
What I did was changing the t4 template and modified the way properties are generated. When property code text is being written you have the information about association and foreign key related to it. Foreign key names are unique in database and I named those with following pattern
FK_[Table]_[Meaning]
...
FK_ProfileHistory_InitialProfile
FK_ProfileHistory_UpdatedProfile
Next, having this information, I named the properties with the [Meaning] part of the foreign key name.

Creating entity relationship with renamed fields and non-primary key in primary table

The following are two partial tables in which I am trying to define a foreign key relationship.
public class Form
{
[Key, Column("FormID")]
public System.Guid FormGUID { get; set; }
[Column("PatGUID")]
public Nullable<System.Guid> PatientGUID { get; set; }
}
public class Patient
{
[Column("PatGUID")]
public System.Guid PatientGUID { get; set; }
[Key, Column("PatID")]
public int PatientID { get; set; }
}
I've eliminated all but the relevant information, fields, navigations, etc. for this example; hopefully not too much.
We have a table Form, with a FK of PatGUID to a Patient table with field PatGUID.
The Patient table has a PatID int KEY field.
We have requirements to rename our fields for our code first entity models; the relevant fields in this example needing changed is PatGUID being changed to PatientGUID.
The difficulty I am having is trying to define this foreign key using either annotations or fluent.
So the end result I need is:
Primary Key Table: Patient, Field: PatGUID (renamed PatientGUID)
Foreign Key Table: Form, Field: PatGUID (renamed PatientGUID)
This doesn’t seem like it should pose a large problem but with the combination of Patient.PatGUID not being the primary key and the PatGUID fields being renamed to PatientGUID has not enabled the WCF Data Service to properly create a reference with a proper reference thus a proper select/join of:
SELECT … FROM [dbo].[Form] AS [Extent1]
INNER JOIN [dbo].[Patient] AS [Extent2] ON [Extent1].[PatGUID] = [Extent2].[PatGUID]
EF doesn't yet support relationships where the principal's key is not the primary key but some other column with a unique key constraint. It is on the feature request list but neither implemented nor on the road map for the next release (EF 6). If it gets implemented at all (in EF 7 maybe) expect to wait a year or more until it's ready for production.
In your particular model EF doesn't recognize any relationship between Form and Patient at all because Patient.PatientID is marked as [Key], not Patient.PatientGUID, and EF treats Form.PatientGUID as an ordinary scalar property, not as an FK to Patient.
In theory you could fake Patient.PatientGUID as the [Key] property in the model although it is not the primary key in the database if you don't create the model from the database or the database from a code-first model, that is, if you map between model and (existing) database manually. But I am not sure if this wouldn't cause subtle problems anywhere else.
The alternative is to write manual join statements in LINQ if you want to fetch Patients and related Forms. You can then join two entities using arbitrary properties, not only key properties. This is, in my opinion, the cleaner and less "tricky" approach. However, the downside is that you won't have navigation properties - references or collections - between Patient and Form and you can't use features like eager loading (Include), lazy loading or comfortable "dotted path syntax" (like Form.Patient.SomePatientProperty, etc.) in your LINQ queries.

In what scenarios do I need foreign keys AND navigation properties in entity framework

My Order class has:
public int CustomerId { get; set; }
public Customer Customer { get; set; }
Do I really need both properties to make a relation working?
I am not using disconnected entities, I am using code first approach.
According to Julia Lerman's book: Programming Entity Framework: DbContext, the difference lies at the difficulty of updating the navigation property. In page 85, She suggests "If there is one thing you can do to make your life easier in N-Tier scenarios, it’s to expose foreign key properties for the relationships in your model." The book includes samples for both scenarios.
The reason is that including a foreign key property tells Entity Framework to use Foreign Key Association, which is simpler than using the so-called Independent Association when you need to update the relationship, i.e., changing the order from one customer to another in your example. With foreign key association, all you need to do is changing the CustomerId. Without the CustomerId foreign key, you need more steps. The independent association uses the ObjectStateManager that is explained Code First: Independent associations vs. Foreign key associations? The ObjectStateManager is complex and is not even exposed from DbContext API.

Can this mapping be done with (Fluent) NHibernate?

I have an Events table whose goal is to store actions done by web site users. An action basically alters or create a new row in a table X. This will allow me to store an history of all actions done by a user. As such, Events contains:
a primary key column
a text to describe the event (ex: "posted a comment")
a discrimator column if needed
a foreign key column to another table A
a foreign key column to another table B
....
a foreign key column to another table N
A row in the Events table will have only one of the foreign key columns set, all others will be null (so they are all nullable). The table behaves like an indirection table to the actual table concerned by the event. I don't know if a discriminator is needed since all the information is contained in the foreign key columns.
Tables A to N can be anything. Their domain model class can have a common interface if necessary (IEventRecordable).
My question is:
Is a mapping possible between the Events table and an Event class? Is it especially feasible with fluent nhibernate? Can it be done without having to create many derived classes of Event (I don't want to create so many empty subclasses)? The Event class would ideally be as follows:
public class Event
{
public virtual int Id { get; set; }
public virtual IEventRecordable ActualEvent { get; set; }
public virtual string EventDescription { get; set; }
DateTime EventDateTime { get; set; }
}
Many classes among the domain model classes could implement IEventRecordable (which is mainly an empty interface). It could be the User table or a BlogComment table...
Thanks
If you forget about the multiple foreign key columns, you can make this an <any> mapping.

Categories

Resources