Kevin Fizz
Kevin Fizz

Reputation: 197

Adding an Index in Entity Framework 7 with Code First Migrations on a field that is a Foreign Key

I think this is going to be easy (famous last words) but I'm new to EF7 and the Code First concept in general and .Net 5 and EF7 is relatively new at this point as well so there's not much out there yet. I'm converting a project from old school ASP 2.0 to .Net 5 and I'm recreating the whole database structure so Code First Migrations is good choice for me here.

I have an AdvertisementHistory table that links back to an Advertisement table and for every Advertisement record there will be a record in the AdvertisementHistory table for every month of every year the ad is running. I'm basically tracking Ad "Hit Counts" by month and year. I want to put a unique index in AdvertisementHistory on "AdvertisementID, Year, Month" and I certainly know how to do this in SQL, but EF Code First is yelling at me the way that I'm doing:

public class Advertisement
{
    public int ID { get; set; }

    [Required]
    public string ImageURL { get; set; }

    [Required]
    public string DestinationURL { get; set; }

    {{....Removing other fields you don't care about}}
}

public class AdvertisementHistory
{
    public int ID { get; set; }

    [Required]
    public Advertisement Advertisement { get; set; }

    [Required]
    public int Year { get; set; }

    [Required]
    public int Month { get; set; }

    [Required]
    public int Clicked { get; set; }

    {{....Removing other fields you don't care about}}
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<Advertisement> Advertisements { get; set; }
    public DbSet<AdvertisementHistory> AdvertisementHistory { get; set; }
    {{....Removing other classes you don't care about}}

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<AdvertisementHistory>()
            .HasIndex(p => new { p.Advertisement, p.Year, p.Month })
            .IsUnique();
    }
}

Then I break out the Command Window since we don't have a project console for .Net 5 EF7 yet:

CMD> dnx ef migrations add Initial_FS

Here are the results:

{{....A bunch of stuff gets generated properly}}

The property 'Advertisement' cannot be added to the entity type 'AdvertisementHistory' because a navigation property with the same name already exists on entity type 'AdvertisementHistory'.

So if I remove "p.Advertisement" from my .HasIndex call everything works fine and it generates the code to make a proper index (although a bad one since I need the Ad ID). But it means this is definitely related to the fact them I'm using a field in my index that is a Foreign Key. I've tried a TON of different variations and annotations on the classes but nothing gets me a clean migration.

As you can see I'm trying very hard to code this from a minimalist perspective and letting .Net "Do its thing" wherever I can. This is why I think I'm missing something very simple here since this is not an unusual concept.

And in case you're wondering this (for the most part) is an initial migration since the only tables that currently exist in the database are the ones you get from AspNet.Identity.

Thanks in advanced community...

Upvotes: 0

Views: 2290

Answers (1)

James Dev
James Dev

Reputation: 3009

Try this. What you really want is to add a foreign key annotation for Advertisement and use this in your index:

public class Advertisement
{
    public int ID { get; set; }
    [Required]
    public string ImageURL { get; set; }
    [Required]
    public string DestinationURL { get; set; }
}

public class AdvertisementHistory
{
    public int ID { get; set; }
    public int AdvertisementID { get; set; }
    [Required]
    [ForeignKey("AdvertisementID")]
    public Advertisement Advertisement { get; set; }
    [Required]
    public int Year { get; set; }
    [Required]
    public int Month { get; set; }
    [Required]
    public int Clicked { get; set; }
}

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<AdvertisementHistory>()
        .HasIndex(p => new { p.AdvertisementID, p.Year, p.Month })
}  

Upvotes: 2

Related Questions