Code-first: Mapping entities to existing database tables - c#

I am using Entity Framework 6 code-first with an existing database, but having problems mapping my entities to the database tables.
Normally, I would use database-first approach and have my entity and context code generated, but using the designer has become a huge pain.
I have set Database.SetInitializer(null) as I do not want EF to change my schema.
Database schema:
Code-first:
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class ReleaseControlContext : DbContext
{
public ReleaseControlContext()
: base(ConfigurationManager.ConnectionStrings["ReleaseControl"].ConnectionString)
{
Database.SetInitializer<ReleaseControlContext>(null);
}
public DbSet<Project> Projects { get; set; }
}
Calling code:
using(var context = new ReleaseControlContext())
{
var projects = context.Projects.ToList();
}
The following exception is thrown:
SqlException: Invalid object name 'dbo.Projects'.
This is because my database table is Project and not Projects. I don't want to rename my context's DbSet<Project> to "Project" because that would be semantically incorrect.
Question:
Do I have to use the fluent API/data annotations to map between the Project database table and the DbSet<Project> Projects collection?

You can use the
[Table("Project")]
public class Project {
....
}
annotation against the Project entity, or in the OnModelCreating(DbModelBuilder modelBuilder) you can call modelBuilder.Entity<Project>().ToTable("Project");.
Both would do the same thing.

You should define a class (ie:ProjectMap) that inherits from the generic class EntityTypeConfiguration(T) where T is here your Project class.
In this ProjectMap class, you can define explicitly a table mapping :
this.ToTable("Project", "dbo");
The class ProjectMap should be called in the following method of your DbContext class
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ProjectMap());
}

Related

cannot perform override in class inheritance in ADO .NET Entity Model edmx

I have to build a .net web application accessing tables of an existing db.
The db uses different tables for different companies: customers in company "ACorp" are stored in table "ACorpCustomers", those in company "B" are stored in table "BCorpCustomers".
Using ADO .NET Entity Model, I created a different Db Context for each Company:
public partial class ACorpContext : DbContext
{
public ACorpContext()
: base("name=ACorpContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<ACorpCustomer> ACorpCustomers { get; set; }
}
}
The edmx generates also the class
public partial class ACorpCustomer
{
public string Name { get; set; }
public string Phone { get; set; }
}
I created a parent class Customer to be used in the application, with the same properties:
public class ACorpCustomer
{
public virtual string Name { get; set; }
public virtual string Phone { get; set; }
}
I havent't found a way to let the specific entity ACorpCustomers inherit from the parent Customer; the edmx returns the inheritance error, but there is no way to override the properties.
Update
In order to avoid edmx file usage, this is what I finally tried out:
I disabled the __MigrationHistory sql table creation using the AutomaticMigrationsEnabled parameter:
internal sealed class Configuration : DbMigrationsConfiguration<MyDomain.Models.ACorpContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
I disabled the db initialization in the App.config file setting
disableDatabaseInitialization="true"
Then I added a an ADO .NET Entity Model but chose the "code first from database".
In order to be sure not to change the db from the model, I disabled the DB Initializer:
public ACorpContext()
: base("name=ACorpContext")
{
Database.SetInitializer<ACorpContext>(null);
}
Now I expect to be my responsability to be keep in sync the domain model with the db.
Anyway, I feel sure that in case of misalignment no attempt will be done to modify the db.
Without the edmx, I have no more limitations defining inheritance from an abstract class Customer.
I cannot understand why Visual Studio considers this as "Code First" approach, anyway.
Your definition
public partial class ACorpCustomer
has nothing to do with inheritance. partial is a .NET moderator that signifies that your class definition is a part of the bigger definition. For example if you have your class split between 2 code files. .Net "puts" them together and you endup with one type
Here what you seem need to do is
public abstract class Customer
{
public string Name { get; set; }
public string Phone { get; set; }
}
public class ACorpCustomer : Customer
{
// may be, some unique properties here
}
public class BCorpCustomer : Customer
{
// may be, some unique properties here
}
The properties Name and Phone don't even need to be virtual. Looking back into your title, there is nothing that you need to override. Nothing that I see..
This is trivial in Code-First, which you can (and should) use with an existing database. Just map the single Customer entity to the correct table for each DbContext:
public partial class ACorpContext : MyBaseDbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>().ToTable("ACorpContext");
}
public virtual DbSet<Customer> Customers{ get; set; }
}

Defining many-to-many connection defining ICollection<> only in one class

I have an .NET application with the validation logic outsourced to a .NET Core API. There are some models and logics that both of them use and I want them to use the same classes from a (.net standard) Nuget package. The main problem that I'm using Entity Framework code-first, and some of the common models are in database too but i don't want to include f.e. ApplicationUser in the nuget package.
There is a model with a many-to-many connection to ApplicationUser and I don't want to define the ICollection in it.
So my "local" class looks something like this:
public class ApplicationUser : IdentityUser
{
....
public ICollection<Institute> Institutes { get; set; }
....
}
And my "remote" class looks like this:
public class Institute
{
....
public ICollection<ApplicationUser> Users { get; set; }
....
}
But I don't want Institute to have this public ICollection<ApplicationUser> Users { get; set; } but I want the EF to map the many-to-many connection. If I delete it from the Institute class the next migration will delete the whole ApplicationUserInstitute connection table.
I have thought of some kind of inheritance solution but I think future development would be pain in the ass with it. Every possible solution is welcomed.
You need explicitly override OnModelCreating() in your context and specify Many-to-Many relation there:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>()
.HasMany(s => s.Institues)
.WithMany()
.Map(cs =>
{
cs.MapLeftKey("UserRefId");
cs.MapRightKey("InstituteRefId");
cs.ToTable("UserInsitute");
});
}
I used entities from this article to generate schema. The only difference is that I removed public virtual ICollection<Student> Students { get; set; } from Course.

No method to map entity to table in entity framework core

I am using entity framework core in a normal .net project, version 4.7. I know I can do this. The problem is that I can't seem to map an entity to a table because the "ToTable" method doesn't exist. I can't edit the poco or entity classes because they are predefined and generated. So I can't use the attribute. I looked on the internet and everyone seems to use this method to map an entity to a table.
Here is my code:
public class FactsDbContext : DbContext
{
public DbSet<TblIncident> TblIncidents { get; set; }
public DbSet<TblAction> TblActions { get; set; }
public DbSet<TblAddressTypeAlias> TblAddressTypeAliases { get; set; }
public DbSet<TblCountry> TblCountries { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//these methods don't exist in my case
modelBuilder.Entity<TblIncident>(entity => entity.ToTable("Incident"));
modelBuilder.Entity<TblIncident>().ToTable("Incident");
}
}
I also tried to use IEntityTypeConfiguration with a EntityTypeBuilder but it still don't have access to the map to table method:
public class IncidentConfig : IEntityTypeConfiguration<TblIncident>
{
public void Configure(EntityTypeBuilder<TblIncident> builder)
{
builder.ToTable("Incident");
}
}
I looked into the Entity Framework Core repository on GitHub and searched for the method "Totable" inside the repository. It turns out it is defined as an extension method but it is in separate nuget package and library called Microsoft.EntityFrameworkCore.SqlServer
After I downloaded the package I got the Totable method that I need. Still it doesn't make sense to add that method in a separate package for sql server when you already have the "Table" attribute that you can add on entities directly in the entity framework core package.
You can use the below approach. You have to use Table data annotation.
DBContext:
public virtual DbSet<Article> Article { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Article>(b =>
{
b.Property(e => e.Property1).HasDefaultValue(true);
... //Other properties
}
Model class:
[Table("Article")]
public class Article
{
You can also use to ToTable in DBContext, but you have to make sure that you have included using Microsoft.EntityFrameworkCore;.
Line modelBuilder.Entity<TblIncident>().ToTable("Incident"); looks correct according to the documentation.
https://learn.microsoft.com/en-us/ef/core/modeling/relational/tables#fluent-api
It's very old thread but I got the same issue and I solved it by placing base.OnModelCreating(builder) as a first line of OnModelCreating method.
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Rest of the code
}

How to know project is code-first or database-first?

In an existing project, how do I know if it's code-first or database-first?
Project has this lines of code:
public class TestDBContext : DbContext
{
public DbSet<Player> Players { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
And project has no .edmx file. If any other details need I will share.
EDIT:
Player.cs class
public class Player
{
public int PlayerID { get; set; }
public string PlayerName { get; set; }
}
EDIT 12.05.2017
IF I change database name from connection string and run project, it creates database with the new name with all tables. May be this will be hit for the answer.
If this is a project is Database-first, there is :
[name].edmx diagram file and with it, [name].Context.tt & .cs
every tables that are translated into class are hidden in tree like .edmx > .tt
in OnModelCreating, there is a throw new UnintentionalCodeFirstException()
If not, all the class issue from the tables are in the project (no tree).
Here I am sharing my observation.
Mainly there are two approaches to implement Entity Framework.
1. Code-first
If chosen, it will create simple .cs file(s) which developers later modifies as per their requirement.
Data-first
If chosen, it will create a [name].edmx file along with hierarchy of different files. It contains .Context.tt and underneath .Context.cs file.
The .Context.cs file will have below snippet which indicates whether induced entity model was empty when created or it was with any database object.
namespace Search
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class XYZ_MSCRMEntities : DbContext
{
public XYZ_MSCRMEntities()
: base("name=xyz_MSCRMEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<AnyDatabaseTableOrView> TableOrViewPluralized { get; set; }
}}
In above snippet, very last line (DbSet property) shows that it has imported database object and that is how it is "Data-first"
If there is no .edmx file, the project is code-first.

Entity Framework entity can't be found in dbcontext auto-generated code

I use entity framework 6.1.3 model first approach.
I needed to design a simple model as following.
Then i generated sql to create the database but i found that my entities sets were not defined in my DbContext. I tried to add them manually but Entity Framework keeps regenerating the following code.
It only generates the abstract entity which is exactly the opposite of what it is designed for.
public partial class UploadsDataModelContainer : DbContext
{
public UploadsDataModelContainer()
: base("name=UploadsDataModelContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<AzureBlobs> AzureBlobs { get; set; }
}
Is this a bug in EF code generator or am i missing a step in model creation ?
Thanks to RicardoPeres i added a class file with the following content and it resolved my problem by avoiding the automatic updates of the DbContext.cs file :
public partial class UploadsDataModelContainer : DbContext
{
public virtual DbSet<Chunk> CHunks { get; set; }
public virtual DbSet<Upload> Uploads { get; set; }
}

Categories