Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF 4.1 RC Code First - Mapping to existing database & specifying foreign key name

I have two classes. A Company has a County set against it:

public class Company
{
    public int Id { get; set; }
    public string CompanyName { get; set; }
    public Country HomeCountry { get; set; }
}

public class Country
{
    public int Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
}

I am trying to map to an existing database where the Company table contains the foreign key of the Country record. So I presumably need to tell code first the name of the foreign key column.

Below is the complete code example. It's currently failing with different exceptions based on different things that I try. There's seems to be a lack of cohesive documentation on this as yet.

So using Code First Fluent API how do I define the name of the foreign key column?

Test app:

Create database as follows: CREATE DATABASE CodeFirst; GO

Use CodeFirst

create table Companies
(
    Id int identity(1,1) not null,
    HomeCountryId int not null,
    Name varchar(20) not null,
    constraint PK_Companies primary key clustered (Id)
)

create table Countries
(
   Id                    int identity(1,1) not null
,  Code                  varchar(4)        not null                
,  Name                  varchar(20)       not null                
,  constraint PK_Countries primary key clustered (Id)         
)

alter table Companies
  add
     constraint FK_Company_HomeCountry foreign key (HomeCountryId)
        references Countries (Id) on delete no action

Now run the following C# app:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity.ModelConfiguration;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data;

namespace CodeFirstExistingDatabase
{

    class Program
    {
        private const string ConnectionString = @"Server=.\sql2005;Database=CodeFirst;integrated security=SSPI;";

        static void Main(string[] args)
        {

            // Firstly, add a country record, this works fine.
            Country country = new Country();
            country.Code = "UK";
            country.Name = "United Kingdom";

            MyContext myContext = new MyContext(ConnectionString);
            myContext.Countries.Add(country);
            myContext.Entry(country).State = EntityState.Added;
            myContext.SaveChanges();
            Console.WriteLine("Saved Country");

            // Now insert a Company record
            Company company = new Company();
            company.CompanyName = "AccessUK";
            company.HomeCountry = myContext.Countries.First(e => e.Code == "UK");

            myContext.Companies.Add(company);
            myContext.Entry(company).State = EntityState.Added;
            myContext.Entry(country).State = EntityState.Unchanged;
            myContext.SaveChanges();

            Console.WriteLine("Saved Company"); // If I can get here I'd he happy!

        }
    }

    public class MyContext
        : DbContext
    {
        public DbSet<Company> Companies { get; set; }

        public DbSet<Country> Countries { get; set; }

        public MyContext(string connectionString)
            : base(connectionString)
        {
            Database.SetInitializer<MyContext>(null);
            Configuration.LazyLoadingEnabled = false;
            Configuration.ProxyCreationEnabled = false;
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new CountryConfiguration());
            modelBuilder.Configurations.Add(new CompanyConfiguration());

            base.OnModelCreating(modelBuilder);
        }
    }

    public class CompanyConfiguration
        : EntityTypeConfiguration<Company>
    {

        public CompanyConfiguration()
            : base()
        {

            HasKey(p => p.Id);
            Property(p => p.Id)
                .HasColumnName("Id")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
                .IsRequired();
            Property(p => p.CompanyName)
                .HasColumnName("Name")
                .IsRequired();
            ToTable("Companies");
        }

    }

    public class CountryConfiguration
        : EntityTypeConfiguration<Country>
    {

        /// <summary>
        /// Initializes a new instance of the <see cref="CountryConfiguration"/> class.
        /// </summary>
        public CountryConfiguration()
            : base()
        {

            HasKey(p => p.Id);
            Property(p => p.Id)
                .HasColumnName("Id")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
                .IsRequired();
            Property(p => p.Code)
                .HasColumnName("Code")
                .IsRequired();
            Property(p => p.Name)
                .HasColumnName("Name")
                .IsRequired();

            ToTable("Countries");
        }

    }

    public class Company
    {
        public int Id { get; set; }
        public string CompanyName { get; set; }
        public Country HomeCountry { get; set; }
    }

    public class Country
    {
        public int Id { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
    }
}

The above fails with the following when saving the country: Invalid column name 'HomeCountry_Id

Any help would be very much appreciated!!

Thanks, Paul.

like image 267
P2l Avatar asked Apr 07 '11 10:04

P2l


People also ask

How do you use code first when an existing database schema?

To use code-first for an existing database, right click on your project in Visual Studio -> Add -> New Item.. Select ADO.NET Entity Data Model in the Add New Item dialog box and specify the model name (this will be a context class name) and click on Add.

How do I change code first to database first?

There is no way to convert your code-first classes into database-first classes. Creating the model from the database will create a whole new set of classes, regardless of the presence of your code-first classes. However, you might not want to delete your code-first classes right away.

How do I know if code first or database first?

The main difference between Code First approach and Database First approach is that the Code First enables you to write entity classes and its properties first without creating the database design first.


1 Answers

public CompanyConfiguration()
{
    //...
    HasRequired(x => x.HomeCountry).WithMany()
        .Map(x => x.MapKey("HomeCountryId"));
}
like image 121
Diego Mijelshon Avatar answered Oct 12 '22 00:10

Diego Mijelshon