简体   繁体   中英

ASP.NET Entity Framework 6 - not seeding data with classes that have a one to many relationship

I'm setting up a database on ASP.NET using Entity Framework 6.1.2 code first method and I'm using Visual Studio 2015. The database is for a project I'm working on for a Marina and I've created two class - Boats and Slips. Each boat is assigned to a slip and each slip contains boats.

The classes are as follows:

    namespace DatabaseTest.Models
{
    public class Boat
    {
        public int BoatID { get; set; }
        public string StateRegoNo { get; set; }
        public double Length { get; set; }
        public string Manufacturer { get; set; }
        public string Model { get; set; }
        public int Year { get; set; }

        [EnumDataType(typeof(BoatType)), Display(Name = "Boat Type")]
        public BoatType type { get; set; }

        public int SlipID { get; set; }

        public virtual Slip Slip { get; set; }
    }

    public enum BoatType
    {
        PowerBoat,
        SailBoat
    }
}

    namespace DatabaseTest.Models
{
    public class Slip
    {
        public int SlipID { get; set; }
        public decimal Length { get; set; }
        public decimal Width { get; set; }

        public virtual ICollection<Boat> Boats { get; set; }
    }
}

Here is the configuration file:

 namespace DatabaseTest.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using DatabaseTest.Models;

    internal sealed class Configuration : DbMigrationsConfiguration<DatabaseTest.Models.MarinaContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(DatabaseTest.Models.MarinaContext context)
        {
            context.Boats.AddOrUpdate(
                new Boat
                {
                    BoatID = 1,
                    StateRegoNo = "TW207332",
                    Length = 20.01,
                    Manufacturer = "Whittley",
                    Model = "Sea Legend 601",
                    Year = 2002,
                    type = BoatType.PowerBoat,
                    SlipID = 1
                },

                new Boat
                {
                    BoatID = 2,
                    StateRegoNo = "NS210451",
                    Length = 48.38,
                    Manufacturer = "Dufour",
                    Model = "500 Grand Large",
                    Year = 2015,
                    type = BoatType.SailBoat,
                    SlipID = 2
                } 
                );

            context.SaveChanges(); 

            context.Slips.AddOrUpdate(

                new Slip
                {
                    SlipID = 1,
                    Width = 10,
                    Length = 20,
                },

                new Slip
                {
                    SlipID = 2,
                    Width = 10,
                    Length = 20,
                }
                );

        }
    }
}

Now running 'add-migration initial' in the Package Manager creates the following migration file:

    namespace DatabaseTest.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class initial : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Boats",
                c => new
                    {
                        BoatID = c.Int(nullable: false, identity: true),
                        StateRegoNo = c.String(),
                        Length = c.Double(nullable: false),
                        Manufacturer = c.String(),
                        Model = c.String(),
                        Year = c.Int(nullable: false),
                        type = c.Int(nullable: false),
                        SlipID = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.BoatID)
                .ForeignKey("dbo.Slips", t => t.SlipID, cascadeDelete: true)
                .Index(t => t.SlipID);

            CreateTable(
                "dbo.Slips",
                c => new
                    {
                        SlipID = c.Int(nullable: false, identity: true),
                        Length = c.Decimal(nullable: false, precision: 18, scale: 2),
                        Width = c.Decimal(nullable: false, precision: 18, scale: 2),
                    })
                .PrimaryKey(t => t.SlipID);

        }

        public override void Down()
        {
            DropForeignKey("dbo.Boats", "SlipID", "dbo.Slips");
            DropIndex("dbo.Boats", new[] { "SlipID" });
            DropTable("dbo.Slips");
            DropTable("dbo.Boats");
        }
    }
}

Then I run 'update-database'. The database and tables are created but then I get the following error: 'An error occurred while updating the entries. See the inner exception for details.' and no data has been added to the tables.

So I'm wondering what has possibly gone wrong here. What is this 'inner exception' and how can I find out what it is?

Can anyone tell me where I've gone wrong?

Thanks

David

Here is the full script from the Package Manager:

    PM> add-migration initial
Scaffolding migration 'initial'.
The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration initial' again.
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201609162249553_initial].
Applying explicit migration: 201609162249553_initial.
Running Seed method.
System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Boats_dbo.Slips_SlipID". The conflict occurred in database "DatabaseTest.Models.MarinaContext", table "dbo.Slips", column 'SlipID'.
The statement has been terminated.
   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.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext`1 c)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
   at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary`2 identifierValues, List`1 generatedValues)
   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
   --- End of inner exception stack trace ---
   at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.<Update>b__2(UpdateTranslator ut)
   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update[T](T noChangesResult, Func`2 updateFunction)
   at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update()
   at System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__35()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
   at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass2a.<SaveChangesInternal>b__27()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
   at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
   at System.Data.Entity.Internal.InternalContext.SaveChanges()
   --- End of inner exception stack trace ---
   at System.Data.Entity.Internal.InternalContext.SaveChanges()
   at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
   at System.Data.Entity.DbContext.SaveChanges()
   at DatabaseTest.Migrations.Configuration.Seed(MarinaContext context) in C:\Users\david\Dropbox\WEB DEVELOPMENT COURSE\1428 OBJECT ORIENTED WEB WEB DEVELOPMENT 1\PROJECTS\PopeyeMarina\DatabaseTest\Migrations\Configuration.cs:line 44
   at System.Data.Entity.Migrations.DbMigrationsConfiguration`1.OnSeed(DbContext context)
   at System.Data.Entity.Migrations.DbMigrator.SeedDatabase()
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.SeedDatabase()
   at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
   at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
   at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.<Update>b__b()
   at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
   at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
   at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
   at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
An error occurred while updating the entries. See the inner exception for details.
PM> 

Ok, now I can see what the inner exception is. At the top it says:

System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Boats_dbo.Slips_SlipID". The conflict occurred in database "DatabaseTest.Models.MarinaContext", table "dbo.Slips", column 'SlipID'.
The statement has been terminated.

Now I just need to resolve this conflict.

You should first be adding the Slip records, as those SlipID's don't exist yet in the database without performing a SaveChanges() on your context.

The code can be further simplified in a single round-trip to the database with the following:

namespace DatabaseTest.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using DatabaseTest.Models;

    internal sealed class Configuration : DbMigrationsConfiguration<DatabaseTest.Models.MarinaContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(DatabaseTest.Models.MarinaContext context)
        {

            context.Boats.AddOrUpdate(
                new Boat
                {
                    BoatID = 1,
                    StateRegoNo = "TW207332",
                    Length = 20.01,
                    Manufacturer = "Whittley",
                    Model = "Sea Legend 601",
                    Year = 2002,
                    type = BoatType.PowerBoat,
                    Slip = new Slip {
                            SlipID = 1,
                            Width = 10,
                            Length = 20,
                    }
                },
                new Boat
                {
                    BoatID = 2,
                    StateRegoNo = "NS210451",
                    Length = 48.38,
                    Manufacturer = "Dufour",
                    Model = "500 Grand Large",
                    Year = 2015,
                    type = BoatType.SailBoat,
                    Slip = new Slip {
                        SlipID = 2,
                        Width = 10,
                        Length = 20,
                    }
                });

            context.SaveChanges(); 

        }
    }
}

The solution is:

    namespace DatabaseTest.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using DatabaseTest.Models;

    internal sealed class Configuration : DbMigrationsConfiguration<DatabaseTest.Models.MarinaContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(DatabaseTest.Models.MarinaContext context)
        {

            context.Slips.AddOrUpdate(

                new Slip
                {
                    SlipID = 1,
                    Width = 10,
                    Length = 20,
                },

                new Slip
                {
                    SlipID = 2,
                    Width = 10,
                    Length = 20,
                }
                );

            context.SaveChanges();

            context.Boats.AddOrUpdate(
                new Boat
                {
                    BoatID = 1,
                    StateRegoNo = "TW207332",
                    Length = 20.01,
                    Manufacturer = "Whittley",
                    Model = "Sea Legend 601",
                    Year = 2002,
                    type = BoatType.PowerBoat,
                    SlipID = 1
                },

                new Boat
                {
                    BoatID = 2,
                    StateRegoNo = "NS210451",
                    Length = 48.38,
                    Manufacturer = "Dufour",
                    Model = "500 Grand Large",
                    Year = 2015,
                    type = BoatType.SailBoat,
                    SlipID = 2
                } 
                );

            context.SaveChanges(); 

        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM