Working with Schemas in EF Code First Migrations - entity-framework

I suppose this question is a cosmetic one; when you initially create an EF migration, it puts the schema in by default; for example:
public override void Up()
{
DropPrimaryKey("dbo.MyTable");
AddPrimaryKey("dbo.MyTable", "NewField");
This seems fine, unit you see the key name that it generates as a result (it has dbo in the key name).
I realise that one way around this is to specify the key name directly. Are there any other options, for example, can the schema be specified for a block, but not included in the specific modifications? For example:
public override void Up()
{
UseSchema("dbo");
DropPrimaryKey("MyTable");
AddPrimaryKey("MyTable", "NewField");
I realise that you can simply omit the schema name; i.e., this will work:
public override void Up()
{
DropPrimaryKey("MyTable");
AddPrimaryKey("MyTable", "NewField");
But how would I then deal with a situation where there were more than a single schema?

You can specify default schema using HasDefaultSchema method on DbModelBuilder class instance.
modelBuilder.HasDefaultSchema("schemaName");
You can also set schema for each entity using ToTable method on EntityTypeConfiguration<TEntityType> class instance. Which will generate migration scripts with provided schema for desired entity/ies.
modelBuilder.Entity<TEntity>().ToTable("tableName", "schemaName")
You can also use Table attribute to set schema for entity.
[Table("tableName","schemaName")]
Or you can write your own custom convention
public class DynamicSchemaConvention : Convention
{
public CustomSchemaConvention()
{
Types().Configure(c => c.ToTable(c.ClrType.Name, c.ClrType.Namespace.Substring(c.ClrType.Namespace.LastIndexOf('.') + 1)));
}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new CustomSchemaConvention());
}
Related links:
DbModelBuilder.HasDefaultSchema Method
EntityTypeConfiguration.ToTable Method
TableAttribute Class
Entity Framework 6 - Code First: table schema from classes' namespace
Entity Framework Custom Code First Conventions (EF6 onwards)

Related

Change MigrationsHistoryTable column names in EF Core

I have a standardized all table and column names in my EF Core database to use snake_case. I was able to change the migrations history table name and schema to match the rest of the database, but I am not able to find a way to change the columns from MigrationId to migration_id and ProductVersion to product_version.
Any ideas on how this could be done?
Here is an example of how to do it on SQL Server.
First, create a custom implementation of SqlServerHistoryRepository overriding ConfigureTable.
class MyHistoryRepository : SqlServerHistoryRepository
{
public MyHistoryRepository(
IDatabaseCreator databaseCreator, IRawSqlCommandBuilder rawSqlCommandBuilder,
ISqlServerConnection connection, IDbContextOptions options,
IMigrationsModelDiffer modelDiffer,
IMigrationsSqlGenerator migrationsSqlGenerator,
IRelationalAnnotationProvider annotations,
ISqlGenerationHelper sqlGenerationHelper)
: base(databaseCreator, rawSqlCommandBuilder, connection, options,
modelDiffer, migrationsSqlGenerator, annotations, sqlGenerationHelper)
{
}
protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
{
base.ConfigureTable(history);
history.Property(h => h.MigrationId).HasColumnName("migration_id");
history.Property(h => h.ProductVersion).HasColumnName("product_version");
}
}
Then replace the replace the service with your custom implementation.
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options
.UseSqlServer(connectionString)
.ReplaceService<SqlServerHistoryRepository, MyHistoryRepository>();

Ignore Entities by Default

I have an existing database, to which I'd like to add Entity Framework mappings for just a handful of tables/entities. Is there a way to ignore all entities by default, and then selectively include them?
I have this in the context constructor to not migrate changes:
Database.SetInitializer(new NullDatabaseInitializer<Context>());
And then I have the following fluent code to map the existing entities:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Cube>()
.Map(e => e.ToTable("tblCubes"))
.HasKey(e => e.CubeId);
...
However, when I run any EF queries, I get the error:
One or more validation errors were detected during model generation.
EntityType 'xyz' has no key defined. Define the key for this EntityType
Rather than using modelBuilder.Ignore<xyz>(); on every existing and future entity, can't I just get EF to ignore all by default, and only map those I choose/include?
EDIT============
One of my EF entities (CubeFact) has relational properties to other classes like this one below to the Year class:
private Year _year;
public Int16 YearId { get; set; }
public Year Year { get { return _year ?? (_year = Year.GetYearById(YearId)); } set { _year = value; } }
The Year class then links to a Fact class, which is one of the classes failing validation. But neither the Year class nor the Fact class have been explicitly mapped. Does EF follow these relationships and then validate, even if I haven't explicitly told it about the relationships?

Can I add a discriminator via a custom code first convention?

I add a discriminator column to all my entities in order to facilitate soft delete.
Currently I do it by specifying it on each entity one by one:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>().Map(m => m.Requires("IsDeleted").HasValue(false));
modelBuilder.Entity<Bar>().Map(m => m.Requires("IsDeleted").HasValue(false));
//etc etc
}
What I'd like to be able to do is specify it as a Custom Code First Convention. My entities all inherit from a ModelBase class. So I can create a custom convention to map to stored procedures like this:
modelBuilder.Types<ModelBase>().Configure(m => m.MapToStoredProcedures());
but this is not available:
modelBuilder.Types<ModelBase>().Configure(m => m.Requires("IsDeleted").HasValue(false));
So, is there any way to add a discriminator to all entities that inherit from ModelBase other than doing it one by one?

EF5 default table name convention causes 'Invalid object name' exception

I have a model with several entities in my MVC4 project with VS 2012. Recently I added a view to my DB named 'vwTeacherNames' and I tried to update the model and I unchecked the Plorizing option for that update.
Then, I rename my entity to 'TeacherName'. Now when I tun the Prj, this exception is thrown where I define a DropDownList for teachers:
Invalid object name 'dbo.TeacherNames'.
I tried many ways such as using custom tool, removing the .tt files and generating the again, ... However the problem stays firm!
So, how can I tell the EF the right table(in fact view) name which is vwTeacherNames?
Thanks a lot
Found it! and I add it here with some more tweaks:
public class myDbContext : DbContext
{
public PtDbContext()
: base("DefaultConnection")
{
}
... //some entities
//Here it is:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<TeacherName>().Property(t => t.FullName)
.HasColumnName("TeacherName");
modelBuilder.Entity<TeacherName>().ToTable("vwTeacherNames", schemaName: "dbo");
}
}
Update: Why waisting your time by defining what you previously defined?! Just kill the default table naming convention and enjoy progressing your Prj:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Adding this line tells the EF not to go through that convention
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
So, It should builds up your queries by EntitySetName and EntityName properties of your entities which the first of is the DB table name and the second is your entity name which you use in your DbContext.

Create an Updatable Model - Entity Framework

I just want to know if there's a way on how to create an Updatable model. Right now, I have to create procedures for insert, update, and delete for all of the tables in my model. This is very tedious so I was wondering if there is one way which I could do to resolve this?
I remember before in my previous work that we used to make models and access them (CRUD) without creating procedures. But i'm not really certain now on how it was made.
Thank you!
There are various ways in which you can automate the generation (on the fly or already generated at compile time) of the actual SQL calls to the database to insert, select, update and delete within the Entity Framework.
You can use the ORM tools (e.g. Linq to Entities) to minimise or eliminate the writing of raw SQL. This means you still have to use the correct attributes on your entities and the properties/methods therein and that's a manual process. (Some backgrounding on this MSDN page)
You can allow the framework to automatically generate your entities based on some existing database schema (only possible with SqlServer-type databases) which basically does 90% of the work for you. There may be some cases where you need to override, for example, the default insert SQL with something custom. This is achieved via the Generate Database Wizard (which I think is a part of Visual Studio 2008+).
You can use POCO classes with EF. If you're using 4.1 and above, you can use the DbContext class. To map your model to the table / columns, simply override OnModelCreating in your context class (which inherits from DbContext). Say you have a model called User, a table called Users, and the context class MyContext, the code could be smth like this:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
}
public class MyContext : DbContext
{
public MyContext() :
base("MyContext")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().
.ToTable("Users");
modelBuilder.Entity<User>().
.Property(d => d.UserId)
.HasColumnName("UserId")
modelBuilder.Entity<User>().
.Property(d => d.UserName)
.HasColumnName("UserName");
}
}
To use it, simply add the User instance to your DbSet, then call SaveChanges:
using(MyContext ctx = new MyContext())
{
var u = new User() { UserId = 1, UserName = "A" };
ctx.Users.Add(u);
ctx.SaveChanges();
}