6
votes

I am using Entity Framework to generate models from existing database tables. In the 'Entity Data Model Wizard' I chose the 'Code First from Database' option to give me the POCO classes. Each class should mirror a database table and contains properties that correspond to the columns in the table.

The thing is, when I run the project I get errors relating to navigation properties that do not exist in the actual database. Theses are typical EF generated navigation properties:

Invalid column name 'Attribute_AttributeId' and Invalid column name 'Shift_ShiftId'

There are no actual fields in the database named as such because (I believe) these dynamic navigation fields are created at runtime:

enter image description here

For completeness, here's the model for 'Driver' which is causing this error. There are quite a few 'virtual' properties that at runtime create a new class (dynamic proxy) to create the logic to load the navigation properties:

namespace IntrinsicDataLoader.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.Spatial;

    public partial class Driver
    {
        public Driver()
        {
            DriverTrackings = new HashSet<DriverTracking>();
            DriverVehicles = new HashSet<DriverVehicle>();
        }

        public int DriverId { get; set; }

        public Guid DriverGuid { get; set; }

        public long ActivityLogId { get; set; }

        [Required]
        [StringLength(10)]
        public string DriverNumber { get; set; }

        public long TransportProvideId { get; set; }

        [Required]
        [StringLength(50)]
        public string FirstName { get; set; }

        [Required]
        [StringLength(50)]
        public string LastName { get; set; }

        public int? ShiftPatternId { get; set; }

        [Required]
        [StringLength(50)]
        public string Password { get; set; }

        [StringLength(50)]
        public string Status { get; set; }

        public DateTime? LastActive { get; set; }

        [StringLength(50)]
        public string DriverType { get; set; }

        [StringLength(50)]
        public string AKA { get; set; }

        [StringLength(500)]
        public string HomeAddress { get; set; }

        [StringLength(100)]
        public string Email { get; set; }

        [StringLength(20)]
        public string MobilePhone { get; set; }

        [StringLength(20)]
        public string OtherPhone { get; set; }

        [StringLength(10)]
        public string Gender { get; set; }

        [StringLength(50)]
        public string Ethnicity { get; set; }

        public DateTime StartDate { get; set; }

        [Required]
        [StringLength(50)]
        public string Badge { get; set; }

        public DateTime BadgeExpiry { get; set; }

        [Required]
        [StringLength(50)]
        public string BadgeType { get; set; }

        [Required]
        [StringLength(50)]
        public string LicenceNumber { get; set; }

        public DateTime LicenceExpiry { get; set; }

        public DateTime? SchoolBadgeExpiry { get; set; }

        [StringLength(20)]
        public string NINumber { get; set; }

        public bool? ApplyVAT { get; set; }

        public decimal? VATRate { get; set; }

        public decimal? Balance { get; set; }

        public decimal? CommissionPercentage { get; set; }

        [StringLength(50)]
        public string PoliceDisclosure { get; set; }

        public DateTime? ProofOfAddressSupplied { get; set; }

        public DateTime? AgreementSignDate { get; set; }

        public int? PhotoId { get; set; }

        public bool? IsActive { get; set; }

        public bool? IsDeleted { get; set; }

        [Column(TypeName = "date")]
        public DateTime? DateUpdated { get; set; }

        [Column(TypeName = "date")]
        public DateTime? DateInserted { get; set; }

        [StringLength(50)]
        public string UpdatedBy { get; set; }

        [StringLength(50)]
        public string InsertedBy { get; set; }

        public virtual DriverActivityLog DriverActivityLog { get; set; }

        public virtual TransportProvider TransportProvider { get; set; }

        public virtual ICollection<DriverTracking> DriverTrackings { get; set; }

        public virtual ICollection<DriverVehicle> DriverVehicles { get; set; }

        public virtual Attribute Attribute { get; set; }

        public virtual Shift Shift { get; set; }
    }
}

There errors are specifically associated with the junction tables I am using. I understand that as the only function of a junction table is to create a many to many relation EF simply converts it to a many-to-many relation - so the junction table itself becomes transparent - like it doesn't exist - yet the ability to access the relationships remains. In support of this, I do not have any generated classes for 'DriverAttribute' or 'DriverShift' but do for the other related tables such as 'Attribute', 'Shift', 'TransportProvider', 'DriverVehicle' etc.

That's all fine but I'm stuck with this error. What do I need to do modify model class to stop the error. From my current position of knowledge everything seems correctly defined.

As the issue occurs when I try to reference the Driver model. Here's a more detailed view of the related tables - including those that do not error:

enter image description here

1
Looks like the FK properties weren't explicitly named in DriverTracking and DriverVehicle. Would you show these classes as well? - Gert Arnold
Happy to post them although the DriverTracking and DriverVehicle relationships are not complaining. The errors are specifically related to the junction tables that EF has 'transformed' to a many-to-many relationship. - ChrisCurrie
Ah of course, I was confused, because I expected to see Attributes and Shifts (plural!) in Driver and I blindly copied the first collection members I found. But that's a useful mistake, because looking more closely now it reveals that Driver has a Attribute and a Shift (singular). Why would the class model generator infer that type of association from the data model? There isn't even a direct FK (??). - Gert Arnold
FK's are present for all relationships. After research I kind of understand why this is happening. It seems if you wish to access a junction table, you need to introduce a new column to the junction table which is not part of a FK or PK. It'll then become an entity in your model. I see the non-complaining tables do just this (see 'DriverVehicles'). This feels like a cop-out but I'm going to do this to avoid the error and follow the info held here: goo.gl/5nJ9Kl. Any better suggestions are welcome as an answer. - ChrisCurrie
You can always modify the mappings manually. The generation tool is just a jump start, it hardly ever generates a model exactly as intended. - Gert Arnold

1 Answers

0
votes

It seems you're missing navigation properties:

public int ShiftId{ get; set; }
public int AttibuteId { get; set; }

These will link your Driver table with those virtual relationships:

 public virtual Attribute Attribute { get; set; }
 public virtual Shift Shift { get; set; }

Regards,