EntityFramework anonymous composite key property name conflict
Asked Answered
L

1

8

I'm using EntityFramework 5 (or 4.3 for .Net Framework 4.0)

In my DbContext object I have already set the correct DbSets and the objects contain proper references to each other. This is not new for me, and things are working well.

Now in this case I have some composite keys that, sometimes, include the foreign key of a table (or object in this case). For this I use the HasKey<>() function on the OnModelCreating method of the DbContext. When these properties have different names, there is no problem, but when these properties have the same name, the migration cannot be done.

An example:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // ...

        modelBuilder.Entity<PatientVisit>().ToTable("PatientVisits");
        modelBuilder.Entity<PatientVisit>().HasKey(x => 
            new { x.Patient.Code, x.Code });

        // ...

        base.OnModelCreating(modelBuilder);
    }

As you can see in the code provided, the object PatientVisit has a property named Code, but this property can be repeated as long as it is repeated with a different patient. The entity Patient also has a key defined named Code.

An anonymous type cannot have two properties inferring the same name (obvious). The typical solution would be to name the properties of the anonymous type like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // ...

        modelBuilder.Entity<PatientVisit>().ToTable("PatientVisits");
        modelBuilder.Entity<PatientVisit>().HasKey(x => 
            new { PatientCode = x.Patient.Code, VisitCode = x.Code });

        // ...

        base.OnModelCreating(modelBuilder);
    }

But doing this, when I try to add a migration this error message is thrown.

The properties expression 'x => new <>f__AnonymousType3`2(PatientCode 
= x.Patient.Code, VisitCode = x.Code)' is not valid. The expression 
should represent a property: C#: 't => t.MyProperty'  VB.Net: 'Function(t)
t.MyProperty'. When specifying multiple properties use an anonymous 
type: C#: 't => new { t.MyProperty1, t.MyProperty2 }'  
VB.Net: 'Function(t) New With { t.MyProperty1, t.MyProperty2 }'.
Lustihood answered 18/12, 2012 at 12:57 Comment(0)
G
0

I think what you need to do here is give PatientVisit a new property PatientCode. Which would be the foreign key to Patient. E.g

    HasRequired<PatientVisit>(v => v.Patient).WithMany()
                                             .HasForeignKey(v => v.PatientCode)

Then you can do

    modelBuilder.Entity<PatientVisit>().HasKey(x => 
        new { x.PatientCode, x.Code });
Gittel answered 18/12, 2012 at 13:15 Comment(3)
I know there are solutions that require me to add manually the Keys and Ids of referenced objects, but that implies "changing" a simple object model to a database-mapping model, and I prefer not to do that.Lustihood
Your solution is similar to the one I have implemented, only that there is no fluent mapping needed because it is done by DataAnnotations. Basically it is using the ForeignKey attribute to attach a declared property to the foreign key of a virtual navigation property... but still it implies that i have to explicitly define the navigation properties and the anchor or foreign key properties. I'd like to have a neat, clean object model without any database-related key properties.Lustihood
For an example of the current-but-not-wanted solution that I am referring to, see this thread where it is very well explained.Lustihood

© 2022 - 2024 — McMap. All rights reserved.