Can't map model with a couple of one to one relations with Entity Framework Core

1

I'm developing my first API with ASP.NET Core, and using Entity Framework Core to model my data. I can't map 2 nested class objects within the parent one.

I've read about one to one, and one to many, but I get nothing when I look for several one to one mappings except some posts that didn't help me.

I've seen these:

Entity Framework table with multiple optional one to one relationships

https://github.com/aspnet/EntityFrameworkCore/issues/5344

This is my model

The Contact class owns 2 class properties address, and contact phone. Then in my dbcontext, I specify both one to one relations. Im using :

Entity Framework Core .NET Command-line Tools 2.2.3-servicing-35854

Sql server 13.0.40001

public class Contact
{
    public long Id { get; set; }
    [MaxLength(40)]
    [Required(ErrorMessage = "Contact name is required ")]
    public string Name { get; set; }
    [Required(ErrorMessage = "Company name is required ")]
    public string Company { get; set; }
    public string Pro`enter code here`fileImageURL { get; set; }
    [Required(ErrorMessage = "Contact Emil is required ")]
    public string Email { get; set; }
    [Required(ErrorMessage = "Birthday is required ")]
    public DateTime BirthDate { get; set; }
    [Required(ErrorMessage = "Contact phone is required ")]
    public ContactPhone ContactPhone { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public long id { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public Contact Contact { get; set; }
    public long AddresssContactForeignKey { get; set; }
}

public class ContactPhone
{
    public long ContactPhoneid { get; set; }
    public string PersonalPhone { get; set; }
    public string WorkPhone { get; set; }
    public Contact Contact { get; set; }
    public long ContactPhonesContactForeignKey { get; set; }
}

My DB context:

public class ContactDbContext : DbContext
{
    public DbSet<Contact> Contacts { get; set; }
    public DbSet<ContactPhone> ContactPhones { get; set; }
    public DbSet<Address> ContactAddress { get; set; }

    public ContactDbContext(DbContextOptions<ContactDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Contact>(e =>
        {
            e.HasOne(x => x.ContactPhone)
                .WithOne(y => y.Contact)
                .HasForeignKey<ContactPhone>(z => 
                z.ContactPhonesContactForeignKey);

            e.HasOne(x => x.Address)
                .WithOne(y => y.Contact)
                .HasForeignKey<Address>(z => 
                z.AddresssContactForeignKey);
        });
    }
}

Then i apply the migration :

PM> Add-Migration Migration2

Microsoft.EntityFrameworkCore.Infrastructure[10403] Entity Framework Core 2.2.3-servicing-35854 initialized 'ContactDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy. To undo this action, use Remove-Migration.

Seems there are no errors, then I update the database

PM> update-database Microsoft.EntityFrameworkCore.Infrastructure[10403]
  Entity Framework Core 2.2.3-servicing-35854 initialized 'ContactDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None Microsoft.EntityFrameworkCore.Database.Command[20101]
  Executed DbCommand (29ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); Microsoft.EntityFrameworkCore.Database.Command[20101]
  Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); Microsoft.EntityFrameworkCore.Database.Command[20101]
  Executed DbCommand (28ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  SELECT [MigrationId], [ProductVersion]
  FROM [__EFMigrationsHistory]
  ORDER BY [MigrationId]; Microsoft.EntityFrameworkCore.Migrations[20402]
  Applying migration '20190323155442_Migration2'. Applying migration '20190323155442_Migration2'. Microsoft.EntityFrameworkCore.Database.Command[20101]
  Executed DbCommand (42ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  ALTER TABLE [ContactPhones] DROP CONSTRAINT [FK_ContactPhones_Contacts_ContactForeignKey]; Microsoft.EntityFrameworkCore.Database.Command[20101]
  Executed DbCommand (40ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  DROP INDEX [IX_ContactPhones_ContactForeignKey] ON [ContactPhones]; Microsoft.EntityFrameworkCore.Database.Command[20101]
  Executed DbCommand (385ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  DECLARE @var0 sysname;
  SELECT @var0 = [d].[name]
  FROM [sys].[default_constraints] [d]
  INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
  WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Contacts]') AND [c].[name] = N'Address');
  IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [Contacts] DROP CONSTRAINT [' + @var0 + '];');
  ALTER TABLE [Contacts] DROP COLUMN [Address]; Microsoft.EntityFrameworkCore.Database.Command[20101]
  Executed DbCommand (17ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  DECLARE @var1 sysname;
  SELECT @var1 = [d].[name]
  FROM [sys].[default_constraints] [d]
  INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
  WHERE ([d].[parent_object_id] = OBJECT_ID(N'[ContactPhones]') AND [c].[name] = N'ContactForeignKey');
  IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [ContactPhones] DROP CONSTRAINT [' + @var1 + '];');
  ALTER TABLE [ContactPhones] DROP COLUMN [ContactForeignKey]; fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
  Failed executing DbCommand (51ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  DECLARE @var2 sysname;
  SELECT @var2 = [d].[name]
  FROM [sys].[default_constraints] [d]
  INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
  WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Contacts]') AND [c].[name] = N'Id');
  IF @var2 IS NOT NULL EXEC(N'ALTER TABLE [Contacts] DROP CONSTRAINT [' + @var2 + '];');
  ALTER TABLE [Contacts] ALTER COLUMN [Id] bigint NOT NULL; System.Data.SqlClient.SqlException (0x80131904): The object 'PK_Contacts' is dependent on column 'Id'. ALTER TABLE ALTER COLUMN Id failed because one or more objects access this column.    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)    at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)    at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()    at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues) ClientConnectionId:7bf3ba67-b8dc-4d76-a11b-c9b5ef584fad Error Number:5074,State:1,Class:16 Failed executing DbCommand (51ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] DECLARE @var2 sysname; SELECT @var2 = [d].[name] FROM [sys].[default_constraints] [d] INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Contacts]') AND [c].[name] = N'Id'); IF @var2 IS NOT NULL EXEC(N'ALTER TABLE [Contacts] DROP CONSTRAINT [' + @var2 + '];'); ALTER TABLE [Contacts] ALTER COLUMN [Id] bigint NOT NULL; System.Data.SqlClient.SqlException (0x80131904): The object 'PK_Contacts' is dependent on column 'Id'. ALTER TABLE ALTER COLUMN Id failed because one or more objects access this column. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)    at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)    at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()    at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)    at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)    at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)    at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)    at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)    at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)    at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_1.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action) ClientConnectionId:7bf3ba67-b8dc-4d76-a11b-c9b5ef584fad Error Number:5074,State:1,Class:16 The object 'PK_Contacts' is dependent on column 'Id'. ALTER TABLE ALTER COLUMN Id failed because one or more objects access this column.

And this is the resulting Migration

public partial class Migration2 : Migration
 {
     protected override void Up(MigrationBuilder migrationBuilder)
     {
         migrationBuilder.DropForeignKey(
             name: "FK_ContactPhones_Contacts_ContactForeignKey",
             table: "ContactPhones");

         migrationBuilder.DropIndex(
             name: "IX_ContactPhones_ContactForeignKey",
             table: "ContactPhones");

         migrationBuilder.DropColumn(
             name: "Address",
             table: "Contacts");

         migrationBuilder.DropColumn(
             name: "ContactForeignKey",
             table: "ContactPhones");

         migrationBuilder.AlterColumn<long>(
             name: "Id",
             table: "Contacts",
             nullable: false,
             oldClrType: typeof(int))
             .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
             .OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

         migrationBuilder.AlterColumn<long>(
             name: "ContactPhoneid",
             table: "ContactPhones",
             nullable: false,
             oldClrType: typeof(int))
             .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
             .OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

         migrationBuilder.AddColumn<long>(
             name: "ContactPhonesContactForeignKey",
             table: "ContactPhones",
             nullable: false,
             defaultValue: 0L);

         migrationBuilder.CreateTable(
             name: "ContactAddress",
             columns: table => new
             {
                 id = table.Column<long>(nullable: false)
                     .Annotation("SqlServer:ValueGenerationStrategy",
SqlServerValueGenerationStrategy.IdentityColumn),
                 AddressLine1 = table.Column<string>(nullable: true),
                 AddressLine2 = table.Column<string>(nullable: true),
                 City = table.Column<string>(nullable: true),
                 State = table.Column<string>(nullable: true),
                 AddresssContactForeignKey = table.Column<long>(nullable: false)
             },
             constraints: table =>
             {
                 table.PrimaryKey("PK_ContactAddress", x => x.id);
                 table.ForeignKey(
                     name: "FK_ContactAddress_Contacts_AddresssContactForeignKey",
                     column: x => x.AddresssContactForeignKey,
                     principalTable: "Contacts",
                     principalColumn: "Id",
                     onDelete: ReferentialAction.Cascade);
             });

         migrationBuilder.CreateIndex(
             name: "IX_ContactPhones_ContactPhonesContactForeignKey",
             table: "ContactPhones",
             column: "ContactPhonesContactForeignKey",
             unique: true);

         migrationBuilder.CreateIndex(
             name: "IX_ContactAddress_AddresssContactForeignKey",
             table: "ContactAddress",
             column: "AddresssContactForeignKey",
             unique: true);

         migrationBuilder.AddForeignKey(
             name: "FK_ContactPhones_Contacts_ContactPhonesContactForeignKey",
             table: "ContactPhones",
             column: "ContactPhonesContactForeignKey",
             principalTable: "Contacts",
             principalColumn: "Id",
             onDelete: ReferentialAction.Cascade);
     }

     protected override void Down(MigrationBuilder migrationBuilder)
     {
         migrationBuilder.DropForeignKey(
             name: "FK_ContactPhones_Contacts_ContactPhonesContactForeignKey",
             table: "ContactPhones");

         migrationBuilder.DropTable(
             name: "ContactAddress");

         migrationBuilder.DropIndex(
             name: "IX_ContactPhones_ContactPhonesContactForeignKey",
             table: "ContactPhones");

         migrationBuilder.DropColumn(
             name: "ContactPhonesContactForeignKey",
             table: "ContactPhones");

         migrationBuilder.AlterColumn<int>(
             name: "Id",
             table: "Contacts",
             nullable: false,
             oldClrType: typeof(long))
             .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
             .OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

         migrationBuilder.AddColumn<string>(
             name: "Address",
             table: "Contacts",
             nullable: false,
             defaultValue: "");

         migrationBuilder.AlterColumn<int>(
             name: "ContactPhoneid",
             table: "ContactPhones",
             nullable: false,
             oldClrType: typeof(long))
             .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
             .OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

         migrationBuilder.AddColumn<int>(
             name: "ContactForeignKey",
             table: "ContactPhones",
             nullable: false,
             defaultValue: 0);

         migrationBuilder.CreateIndex(
             name: "IX_ContactPhones_ContactForeignKey",
             table: "ContactPhones",
             column: "ContactForeignKey",
             unique: true);

         migrationBuilder.AddForeignKey(
             name: "FK_ContactPhones_Contacts_ContactForeignKey",
             table: "ContactPhones",
             column: "ContactForeignKey",
             principalTable: "Contacts",
             principalColumn: "Id",
             onDelete: ReferentialAction.Cascade);
     }
 }

Finally the console throws this :

Error Number:5074,State:1,Class:16
The object 'PK_Contacts' is dependent on column 'Id'.
ALTER TABLE ALTER COLUMN Id failed because one or more objects access this column.

I expect the mapping to be 1:1

UPDATE

Ive found the problem. I used to have all my entities Ids beint int, then i changed them to long I started a new project with the written code and started a new database with a first migration and it worked THanks to everyone that was so nice to help me through it !!

c#
entity-framework-core
asked on Stack Overflow Mar 23, 2019 by Maximo Gonzalez • edited Mar 23, 2019 by Maximo Gonzalez

1 Answer

0

UPDATE

Ive found the problem. I used to have all my entities Ids beint int, then i changed them to long I started a new project with the written code and started a new database with a first migration and it worked Thanks to everyone that was so nice to help me through it !!

answered on Stack Overflow Mar 23, 2019 by Maximo Gonzalez

User contributions licensed under CC BY-SA 3.0