Using EF code-first migrations when design model is DB first? - entity-framework

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.

Related

EF Core migration

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);
}
}

How to create Table per type inheritance in Entity Framework Core 2.0 code first?

Following code generates only single table "CertificateEvent".
How do I achieve TPT inheritance in EF Core 2.0?
public abstract class CertificateEvent {
public int CertificateEventId { get; set; }
}
public class Assignment : CertificateEvent {...}
public class Assessment : CertificateEvent {...}
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
public DbSet<Assessment> AssessorAssessments { get; set; }
public DbSet<Assignment> AssessorAssignments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<CertificateEvent>().ToTable(nameof(CertificateEvent));
modelBuilder.Entity<Assessment>().ToTable(nameof(Assessment));
modelBuilder.Entity<Assignment>().ToTable(nameof(Assignment));
}
}
class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<MyDbContext>();
builder.UseSqlServer("Server=(local);Database=Test;Trusted_Connection=True;MultipleActiveResultSets=true");
return new MyDbContext(builder.Options);
}
}
I've also tried dotnet ef migrations add Inheritance, but it did not created TPT inheritance in the database
TPT is not in EF Core (yet). See
The feeling from our team is that TPT is generally an anti-pattern and
results in significant performance issues later on. While enabling it
may make some folks "happier" to start with it ultimately just leads
to issues. We are willing to consider it though, so we're leaving this
open and will consider it based on the feedback we get.
https://github.com/aspnet/EntityFrameworkCore/issues/2266

Unable to query new table from asp.net core web application using EF 1.0

I have developed a new asp.net Core web application using Visual Studio 2015. I am at the point where I am adding user customization options by adding additional tables to my local database. However I have been unable to add whatever EF needs to query a new table correctly. I get the following error when attempting to query the table..
Applying existing migrations for ApplicationDbContext may resolve this issue
There are migrations for ApplicationDbContext that have not been applied to the database
•00000000000000_CreateIdentitySchema
Apply Migrations
In Visual Studio, you can use the Package Manager Console to apply pending migrations to the database:
PM> Update-Database
Alternatively, you can apply pending migrations from a command prompt at your project directory:
dotnet ef database update
My table is a simple table with a few varchar or nvarchar columns. The model looks something like...
namespace MyNamespace.ColorSchemes
{
public class ColorSchemesViewModel
{
[Required]
public string Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string bc { get; set; }
}
Table looks something like this in SQL Server...
CREATE TABLE [dbo].[ColorSchemes](
[Id] [nvarchar](50) NOT NULL,
[Name] [varchar](32) NOT NULL,
[bc] [nchar](7) NOT NULL
)
I have added the table to the application context like such...
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<ColorSchemesViewModel> Colors { get; set; }
I have also used as separate class similarly like..
public DbSet<ColorSchemes> Colors { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
I have added the context to a controller like this...
private ApplicationDbContext _context;
public MyController(IMemoryCache memoryCache, ILoggerFactory loggerFactory, ApplicationDbContext context)
{
_memoryCache = memoryCache;
_logger = loggerFactory.CreateLogger<ChordMVCController>();
_context = context;
}
I have tried to query the table in my controller like this...
var colorSchemes = (from c in _context.Colors
select c).ToList();
I have attempted to use the Package Manager to per instructions from the error...
PM> Update-Database
I always get this error...
System.Data.SqlClient.SqlException: There is already an object named 'AspNetRoles' in the database.
This doesn't make sense since this table is already in the database and the EF definition. How do I get my table added properly to the EF migrations so I can query it?
I was able to solve this myself...
I created a different context rather than trying to embed the dbset in the default ApplicationDbContext and also removed the onModelCreating method.
public class ColorSchemeDbContext : DbContext
{
public ColorSchemeDbContext(DbContextOptions<ColorSchemeDbContext> options) : base(options)
{
}
public DbSet<ColorScheme> ColorSchemes { get; set; }
}
Replaced the ApplicationDBContext with the new context in my controller class...
private readonly ColorSchemeDbContext _context;
public MyController(IMemoryCache memoryCache, ILoggerFactory loggerFactory, ColorSchemeDbContext context)
{
_memoryCache = memoryCache;
_logger = loggerFactory.CreateLogger<ChordMVCController>();
_context = context;
}
After that the query worked. I spent a lot of time attempting to use the EF migrations to create the tables from a class syntax. Nothing seemed to work. I was creating a new .NET CORE web application in VS 2015 with the template and using user authentication which creates the AspNetRoles tables in SqlLite once you do an update-database. It is very confusing how to add additional tables using a code first approach after that. A lot more documentation is needed regarding EF migrations with respect to managing projects over time. I see the benefits of having all of your database updates maintained from your VS project but it is not easy to understand.

There is already an object named 'cars' in the database-data

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.

How to fix "Properties whose types are collection of primitives or complex types are not supported" with EF DbContext?

I have a project containing POCO entities. A database context has been created for it using Entity Framework 4.2 and code first. This works fine, but the context needs to be exposed as an OData service which does not work.
Browsing to the OData service gives this error:
The property 'DataSubmissionItems' on type
'Lifecycle.ProgramReportSubmission.Model.ProgramReportSubmission' is
not a valid property. Properties whose types are collection of
primitives or complex types are not supported.
The data service class looks like:
public class ExceptionReportDataService : DataService<ExceptionReportEntitiesContext>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.UseVerboseErrors = true;
}
}
The EF context class looks like:
public class ExceptionReportEntitiesContext : DbContext
{
public DbSet<ExceptionReport> ExceptionReports { get; set; }
public ExceptionReportEntitiesContext()
: base(DynamicConfig.GetAppSettingValue("DB_CONN_STRING_LIFECYCLE"))
{
}
}
The POCO entities look like:
namespace WBRT.ProgramData.Lifecycle.ExceptionReportModel
{
public class ExceptionReport
{
public virtual Guid ExceptionReportID { get; set; }
public virtual Lifecycle.ProgramReportSubmission.Model.ProgramReportSubmission ReportSubmission { get; set; }
}
}
namespace Lifecycle.ProgramReportSubmission.Model
{
public class ProgramReportSubmission
{
public Guid ProgramReportSubmissionId { get; set; }
public virtual ICollection<DataSubmissionItem> DataSubmissionItems { get; set; }
}
public class DataSubmissionItem
{
public Guid DataSubmissionItemId { get; set; }
}
}
What I've tried:
Setting DataServiceKey on the DataSubmissionItem class
Setting ProxyCreationEnabled to false on the ExceptionReportEntitiesContext constructor as well as in the data service
Overriding OnModelCreating and removing the IncludeMetadataConvention
Overriding OnModelCreating and setting modelBuilder.Entity<ProgramReportSubmission.Model.ProgramReportSubmission>().Ignore(prs => prs.DataSubmissionItems);
Note: I can't introduce a dependency on the EntityFramework DLL in the POCO entities project as this affects referencing projects that still run .NET 3.5.
Anyone know how to resolve this error?
THe RTM version of WCF DS doesn't support these kind of properties. But the latest CTP does. http://blogs.msdn.com/b/astoriateam/archive/2011/10/13/announcing-wcf-data-services-oct-2011-ctp-for-net-4-and-silverlight-4.aspx.
On the other hand, the fact that you get such an error probably means that WCF DS doesn't recognize the provider as EF, and istead works with it as with a reflection provider. So even the latest CTP won't really fix that problem.
WCF DS currently only recognizes EF provider if the T in DataService is ObjectContext or derived type. The typical workaround for EF Code First is to define the service as DataService and then override the CreateDataSource method on it and return the ObjectContext implementation from your DbContext. See this article about how to do that (it's about EF 4.1, but I think the same will apply to 4.2 as well): http://social.technet.microsoft.com/wiki/contents/articles/5234.aspx. You can skip down to the part about WCF DS.