I am developing an MVC project using code first. I create my database using code first as you can see here :
public class DataContext:DbContext
{
public DataContext()
: base("DefaultConnection")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
Database.SetInitializer(
new MigrateDatabaseToLatestVersion<DataContext, MigrationsConfiguration>()
);
}
public DbSet<Member> Members { get; set; }
public DbSet<Traffic> Traffics { get; set; }
public DbSet<Car> Cars { get; set; }
public DbSet<Validation> Validations { get; set; }
public DbSet<Log> Logs { get; set; }
public DbSet<File> Files { get; set; }
}
I uploaded my project in the company server, and they used my project and entered some values to database, so after sometimes I changed some columns in database, and I added normally in SQL design to database table, so I changed some part of my code too, and now then I upload my published file I get this error :
There is already an object named 'Cars' in the database.
Note: I can't delete the database because I have data in it ,as i said I added the new columns to database, but my application can't connect to that database .
Migration part:
public class MigrationsConfiguration : DbMigrationsConfiguration<DataContext>
{
public MigrationsConfiguration()
{
this.AutomaticMigrationDataLossAllowed = true;
this.AutomaticMigrationsEnabled = true;
}
}
As you've got data in your production database already, don't use automatic migrations. Your first priority is to get your databases in sync with your model. How you do this will depend on how complicated your model is, e.g. how many tables. My suggestion would be:
Disable Automatic migrations
Point your dev copy at a blank database, and create an initial migration
Run Update-Database -Script to generate an SQL script for the migration
Alter the script by hand so that it can be run on your production database
Run this on your production database
Once you've got to this point, make sure you add migrations each time you want to make changes to your model, rather than making them by hand.
Related
I have a working web application (an end point) containing a few methods and connected to two tables in sql server. This application is fully implemented from scratch by myself in an ashx file and does not follow any new or old architecture, simply some methods in ashx file that are remotely called and handle requirements of client. There are shared DLLs among client and server for data handling.
For some reasons I want to upgrade client side to Dot Net core, consequently common DLL needs to be upgraded and finally the end point.
Now I'm facing the problem that EF Core only supports code first, but there are ways for scaffolding . I started with Microsoft tutorials. Then I see There are certain ways for migrating and scaffolding existing database, but I got stuck for hours in first step of using command "dotnet ef dbcontext scaffold "Data Source=..." . Then usually tutorial materials get combined with other technologies like asp.net core very fast, I need to read tons of technologies to do a simple task.
I'm worried I'm going the wrong way. there are only two tables and I can implement table structure by hand. Isn't there any sample code that I can modify it's table definitions and I can restart my project soon? If things are so hard, I will omit EF from my project and redefine the whole end point logic by text sql queries.
I can implement table structure by hand.
Great. Simply create a DbContext subtype that has a DbSet for each of your entities. The only thing scaffolding does is save you time.
Here's a complete example for SQL Server:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Order> Orders { get; } = new HashSet<Order>();
}
public class Order
{
public int CustomerId { get; set; }
public int Id { get; set; }
public Customer Customer { get; set; }
}
public class Db : DbContext
{
string connectionString = "Server=localhost; database=efcore5test; integrated security = true;TrustServerCertificate=true;";
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders{ get; set; }
public Db(string connectionString) : base()
{
this.connectionString = connectionString;
}
public Db() : base()
{
this.Database.SetCommandTimeout(180);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var constr = this.connectionString;
optionsBuilder.LogTo(Console.WriteLine);
optionsBuilder.UseSqlServer(constr, o => o.UseRelationalNulls().CommandTimeout(180).UseNetTopologySuite());
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().HasKey(o => new { o.CustomerId, o.Id });
base.OnModelCreating(modelBuilder);
}
}
I have a code first model, e.g.:
public class Cars
{
public int Id { get; set; }
public string Brand { get; set; }
}
My DBContext looks like this:
public class TestDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source = data.db");
}
DbSet<Car> Cars { get; set; }
}
Now when I call "context.Database.Migrate" a _EFMigrationHistory table gets created but no migrations are happening. No tables or columns get created.
And when I call "update-database" in the command line it says "No migrations were applied. The database is already up to date." although there is a "Cars" table to add
What am I doing wrong?
It appears you might have forgotten to create your first migration. Every time you change your object model in a way that needs applied to the database,
you'll need to create a migration - this is not automatic so you can customize the migration code if needed and batch multiple changes into one logical group.
In the package manager console (command line), set your default project to whatever project houses your TestDbContext, and run the add-migration command with a name for the migration, then your project will have a migration to run:
PM> add-migration MyInitalMigration
Package Manager Console Example Image
Real question seems to be here is which is the best way to refresh code first model from DB
Any downsides or alternatives how one could use code first migrations when domain model must reflect DB changes? (eg. in case MDS)
Option 1:
I have tried making POC of migration context is inherited from CodeFirstFromDB context directly.
When one generates EF model from Database the model is separated from migration context eg. dbcontext is not aware that such migrations exist.
Migrations have been enabled for Migration Context only and therefore it will only track changes on it own resx.
public class MigrationInheritedDBContext : ModelCodeFirstFromDB
{
public MigrationInheritedDBContext() : base("name=MigrationInheritedDBContext ")
{
}
}
public partial class ModelCodeFirstFromDB : DbContext
{
public ModelCodeFirstFromDB()
: base("name=ModelCodeFirstFromDB")
{
}
public ModelCodeFirstFromDB(string connectionString) : base(connectionString)
{
}
public virtual DbSet<DMObject1> DMObject1 { get; set; }
public virtual DbSet<DMObject2> DMObject2 { get; set; }
public virtual DbSet<DMObject3> DMObject3 { get; set; }
.
.
.
.
Option 2:
There are T4-templates that will generate db context directly from database.
Any notes, opinions, alternative approaches are welcome, thank you.
I already have a database with tables outside EF scope. But I want that the tables which will be used by EF to be created automatically.
public class SessionInfo
{
public Guid Id {get;set;}
public string Name { get; set; }
public DateTime StartsOn { get; set; }
public DateTime EndsOn { get; set; }
public string Notes { get; set; }
}
public class StudentsDbContext:DbContext
{
public StudentsDbContext():base("name=memory")
{
Database.Log = s => this.LogDebug(s);
}
public DbSet<SessionInfo> Sessions { get; set; }
}
This code just throws an exception because the table SessionInfoes doesn't exist.
using (var db = new StudentsDbContext())
{
db.Sessions.Add(new SessionInfo() {Id = Guid.NewGuid(), Name = "bla"});
var st = db.Sessions.FirstOrDefault();
}
What do I need to do so that EF will create the "SessionInfoes" (whatever name, it's not important) table by itself? I was under the impression that Ef will create the tables when the context is first used for a change or a query.
Update
After some digging, it seems that EF and Sqlite don't play very nice together i.e at most you can use EF to do queries but that's it. No table creation, no adding entities.
EF needs additional information in order to do this. You'll have to specify an IDatabaseInitializer first. Take a look at this list and find one that is appropriate for your needs (for example: MigrateDatabaseToLatestVersion, DropCreateDatabaseAlways, DropCreateDatabaseIfModelChanges, etc).
Then create your class:
public class MyDatabaseInitializer : MigrateDatabaseToLatestVersion
<MyDbContext,
MyDatabaseMigrationConfiguration>
Then also create the configuration for the initializer (ugh right?):
public class DatabaseMigrationsConfiguration
: DbMigrationsConfiguration<MyDbContext>
{
public DatabaseMigrationsConfiguration()
{
this.AutomaticMigrationDataLossAllowed = true;
this.AutomaticMigrationsEnabled = true;
}
protected override void Seed(MyDbContext context)
{
// Need data automagically added/update to the DB
// during initialization?
base.Seed(context);
}
}
Then one way to initialize the database is:
var myContext = new MyDbContext(/*connectionString*/);
Database.SetInitializer<MyDbContext>(new MyDatabaseInitializer());
myContext.Database.Initialize(true);
Some people prefer the to use the command line to migrate databases, but I don't want to assume I'll always have access to the database from a command lin.
I have just upgraded from EF 4.0.0 to EF 4.3.1.
I am using Visual Studio 2010 Ultimate on Windows XP updated to latest release and all Windows updates/patches applied. The database engine I'm using is SQL Server 2008 R2 Developers Edition.
The following code works perfectly under EF 4.0.0 but not under EF 4.3.1.
public class ItemBase
{
public DateTime Created { get; set; }
public int CreatedByUserID { get; set; }
public DateTime LastModified { get; set; }
public int LastModifiedByUserID { get; set; }
public User CreatedBy { get; set; }
public User LastModifiedBy { get; set; }
public ItemBase()
{
CreatedByUserID = -1;
LastModifiedByUserID = -1;
CreatedBy = null;
LastModifiedBy = null;
}
}
public class User : ItemBase
{
public int UserID { get; set; }
public string LoginName { get; set; }
public string Password { get; set; }
public string EmailAddress { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string DisplayName { get; set; }
public User() : base()
{
UserID = -1;
LoginName = String.Empty;
Password = String.Empty;
EmailAddress = String.Empty;
Firstname = String.Empty;
Lastname = String.Empty;
DisplayName = String.Empty;
}
}
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().Property(u => u.UserID).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity);
}
The only thing that has changed is the version of Entity Framework I'm using.
I have checked the references etc and everything is as expected.
As you can see from the code above, the User class inherits from ItemBase which in turn has a reference to a User instance. The underlying User table contains all the properties from the User class and the ItemBase class (except for the two navigation properties public User CreatedBy { get; set; } and public User LastModifiedBy { get; set; })
Running this code under 4.0.0 everything works as expected, not a single problem or issue whatsoever.
BUT, when I run the same code under 4.3.1 (without any changes whatsoever to anything else, including the database I'm using) I get the following error:
"Unable to determine the principal end of an association between the types 'User' and 'User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations."
So I then added the following two lines to the OnModelCreating method:
modelBuilder.Entity<User>().HasRequired(u => u.CreatedBy).WithMany().HasForeignKey(k => k.CreatedByUserID);
modelBuilder.Entity<User>().HasRequired(u => u.LastModifiedBy).WithMany().HasForeignKey(k => k.LastModifiedByUserID);
I then get these strange errors:
"The provider did not return a ProviderManifestToken string."
"A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)"
I also noticed loads and loads of these errors in the output window:
"A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll"
However, these errors appear to be a bit of a red-herring, as the database is fine, available, and the connection string is perfect too. If I subsequently undo the changes to the OnModelCreating method I get the original error again, so I don't believe the error messages I'm getting actually reflect the underlying problem that's occurring here.
So, based on all of this, I come to the following conclusions:
There is a bug in version 4.3.1 of the Entity Framework?
The fact that my code worked under 4.0.0 without the extra two lines
in the OnModelCreating method was probably due to checks not being
made in 4.0.0 which are now subsequently being made in 4.3.1?
I need to add something extra to my configuration/code, or I'm
missing something else to make this work again under 4.3.1?
Can anyone shed some light on this for me? Its driving me nuts!
Many thanks for your time on this.
Kind Regards
Steve
It looks like you have been using a pre-release version of EF 4.1. Probably CTP4 or CTP5. This is apparent because:
ModelBuilder was renamed to DbModelBuilder before 4.1 RTM
DatabaseGenerationOption was renamed to DatabaseGeneratedOption
The exception you are seeing was introduced before EF 4.1 was RTM'ed
Given this, I'm not 100% sure what model was being created with the pre-release version you were using. With 4.1 and above the two navigation properties are detected as inverses of each other and Code First tries to make a 1:1 relationship between User and User. Code First cannot determine the principal for this relationship so rather than guessing it throws asking you to provide it.
However, looking at your model it is clear that this is not what you want anyway. It seems much more likely that you want two 1:* uni-directional navigation props--one for CreatedBy and one for LastModifiedBy. This is what you setup in your OnModelCreating call.
With the changes made to the names of the classes to match 4.1/4.3 and with the code added to OnModelCreating, your code works fine for me on EF 4.3.1.
With regard to not being able to make the connection, you say that the connection string is correct, in which case it must be a case of EF not finding it. Assuming it is in your app.config, then you need to pass the name of it to the DbContext constructor. For example:
public class MyContext : DbContext
{
public MyContext()
: base("name=MyConnectionStringName")
{
}
}
If you're using the connection string in some other way then we'll need more details on that.