简体   繁体   中英

Code First with the Entity Framework throws a DbUpdateException when saving

I am trying to create my first database in a Visual Studio C# project and add an entity to this database. I have not yet managed to do so. When trying, I will get a DbUpdateException when calling SaveChanges() on the DbContext .

I am trying to save the following entity:

public class TVSeriesReference : Reference
{
}

TVSeriesReference does nothing but inherit Reference :

public class Reference
{
    /// <summary>
    /// ID of the reference.
    /// </summary>
    public int Id { get; set;  }

    /// <summary>
    /// Reference to the element in theTVDB.
    /// </summary>
    public int TheTVDBId { get; set; }

    /// <summary>
    /// Whether or not the reference has been marked as watched.
    /// </summary>
    public bool IsWatched { get; set; }
}

I am using the following context:

public class Library : DbContext
{
    /// <summary>
    /// Constructor using the base constructor.
    /// This constructor names the database "Library".
    /// </summary>
    public Library() : base("Library")
    {
    }

    /// <summary>
    /// Set of TVSeriesReferences stored in the database.
    /// </summary>
    public DbSet<TVSeriesReference> TVSeriesReferences { get; set; }

    /// <summary>
    /// Set of SeasonReferences stored in the database.
    /// </summary>
    public DbSet<SeasonReference> SeasonReferences { get; set; }

    /// <summary>
    /// Set of EpisodeReferences stored in the database.
    /// </summary>
    public DbSet<EpisodeReference> EpisodeReferences { get; set; }
}

And this is how I try to create and save the entity to the database.

using (var db = new Library())
{
    var reference = new TVSeriesReference
    {
        Id = 2,
        TheTVDBId = 1,
        IsWatched = true
     };

     db.TVSeriesReferences.Add(reference);

     try
     {
         db.SaveChanges();
     }
     catch (DbUpdateException e)
     {
         Debug.WriteLine("\n\n*** {0}\n\n", e.InnerException);
     }
 }

db.SaveChanges() will throw the following exception:

System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Invalid object name 'dbo.TVSeriesReferences'.
   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)
   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.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary`2 identifierValues, List`1 generatedValues)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   --- End of inner exception stack trace ---
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
   at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
   at System.Data.Entity.Internal.InternalContext.SaveChanges()

I have been tearing my hair out for hours and hours now and I can't figure out what I am doing wrong. It seems that the tables (or maybe the entire database?) is not being created. Is there something I should have set up or have installed before this will work? I have installed NuGet and through that the Entity Framework.

Is there anyone who can help me get this to work?

UPDATE : ConnectionStrings in app.config

<connectionStrings>
    <add name="Library"
         connectionString="Data Source=.\SQLEXPRESS"
         providerName="System.Data.SqlServerCe.4.0"/>
  </connectionStrings>

While working with Entity Framework Code First you still need to set proper ConnectionString in your app.config file. For example if you want to have a local database in file, you can use embedded SQL Server CE 4 database engine (of course Code First can be used with many different databases including SQL Server, SQL Server Express and MySQL):

<connectionStrings> 
    <add name="Library" connectionString="Data Source=|DataDirectory|CodeFirst.sdf" providerName="System.Data.SqlServerCe.4.0"/> 
</connectionStrings>

At run time, the DataDirectory substitution string is replaced with the appropriate directory path for the application's current execution environment. Without the DataDirectory substitution string, your application would have to programmatically determine the location of the database file based on the current execution environment and then dynamically build the path used in the connection string.

The Code First has also an auto-recreate functionality which is controlled by initialization strategy. The default initialization strategy is CreateDatabaseIfNotExists . With this strategy if your ConnectionString is pointing to database which doesn't exists Code First will create the database for you, but if the database already exists Code First will not try to create it.

The initialization strategy can be changed with Database.SetInitializer() method to one of the following:

You need to remember here, that recreating database will lead to losing all data that were stored there.

You need to set a database initializer and then initialize the database. Probably the best one to start off with, since this is a new database, is the DropCreateDatabaseAlways one. You can do the following:

Database.SetInitializer(new DropCreateDatabaseAlways<Library>());
using(var db = new Library())
{
  db.Database.Initialize(true);
}

Putting a connection string in the App.config, like @tpeczek said, would also be a good idea to do with this.

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