I am fairly new to Entity Framework and MVC. I can use the Entity Data Model Wizard (EDMW) on an existing SQL server database and automatically create the necessary classes (context, models,etc). Then pass the model (db.Employees.tolist()) to a view from the controller. Everything works fine and I can see the list of all the employees on the browser from the company.employees table.
However, I want to write the code myself without the help of EDMW or other tools to better understand the entity/MVC/database interactions. So I wrote the following code but can't seem to get the table displayed on the browser. I know I am missing something.
SQL SERVER:
Schema.tablename (Acme.Employees)
public class AcmeContext : DbContext
{
public virtual DbSet<Employee> Employees { get; set; }
}
public class Employee
{
public int customerid {get; set;}
public string name {get;set;}
public string state {get;set;}
}
public ActionResult list()
{
var db = new AcmeContext();
return view(db.Employees.tolist());
}
<connectionStrings>
<add
name="AcmeContext"
connectionString="data source=localhost;initial catalog=Acme;integrated security=True;"
providerName="System.Data.SqlClient" />
</connectionStrings>
What else is needed?
Also, how is this done in the real world when the DB already exists? Does the developer use the EDM wizard or manually code everything the wizard does in Visual Studio or other IDE?
By default when you are using Entity Framework code first, the schema is dbo
you can change schema by using using fluent API or Data Anotation
Fluent API :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>().ToTable("Employees", "Acme");
}
Data Anotations
[Table("Employees", Schema = "Acme")]
public class Employee
{
...
}
You don't have a construction calling your connection string
public class AcmeContext : DbContext
{
public AcmeContext() :base(nameOrConnectionString: "AcmeContext"){}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove();
}
public virtual DbSet Employees { get; set; }
}
Your question already answered here. Please refer to this topic
Code-first vs Model/Database-first
I solved my problem.
The EF created a table dbo.employees instead of using the acme.employees. All along it was looking at the employee table in the dbo schema. Of course there is no data in that table and thus the blank web page. I added some data and now can see it on the page.
What I still don't know is the data annotation that Aiska Hendra suggested didn't work earlier.
Related
I have simple data in a container in cosmos db:
{
"id": "fd81aacb-64eb-452b-a0bd-c0395aa8afb6",
"thePartitionKey": "test"
}
When I try to list data with entity framework, it always returns null.
My DbContext looks something like this:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
..... //some configuration
optionsBuilder.UseCosmos(endpoint, accountKey, dbName);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Test>()
.ToContainer("theContainerID")
.HasPartitionKey(e => e.thePartitionKey);
public DbSet<Test>? Tests { get; set; }
}
The Model:
public class Test
{
public string id { get; set; }
public string thePartitionKey { get; set; }
}
The code:
public List<Test> GetDataTest(){
var qry = context.Tests.ToList();
return qry;
}
I have looked at some tutorials here, here, and here but it does not really seem to be different from my code.
What am I missing?
Using a similar example as shared by you in the question. In below screenshot you can see there is a single container in Cosmos DB having single record.
Solution:- As this container (theContainerId) stores a single document, there is no need of discriminator. In case the container has document of same entity type, we can use HasNoDiscriminator() method of Microsoft.EntityFrameworkCore package to get the record.
modelBuilder.Entity<test>()
.ToContainer("theContainerID")
.HasPartitionKey(e => e.thePartitionKey)
.HasNoDiscriminator();
Below is the screenshot of such an example.
As you can see, after modifying the modelBuilder the record is fetched.
It is explained in first link shared by you in question here at 22:16 secs.
Entity framework by default adds a discriminator value
("Discriminator" : "{modelName}" in current scenario it will be
test) while creating the object, when you have multiple entity type of documents in the same cosmos DB container.
To get more information you can refer links available under reference section.
References :-
EF Core Azure Cosmos DB Provider
Azure CosmosDB + CRUD + Entity Framework Core - FREE
I have simple context with 3 tables.
database tables are already present but using code first approach.
Model Device.cs is -
public class Device
{
public System.Guid Id { get; set; }
public string Name{ get; set; }
}
public class sampledbContext : DbContext
{
public sampledbContext ()
: base("name=sampledbContext ")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public virtual DbSet<Device> Devices { get; set; }
}
To avoid extra s I have added above line into OnModelCreating but it is giving an error -
System.InvalidOperationException: 'The model backing the 'sampledbContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).'
Database was already created and I try to use code first approach here.
I have not done update-database yet.
I tried doing Enable-Migration and Update-database it creates table with name s like Devices why ? s is added ?
You've turned off auto-migrations in the line:
Database.SetInitializer<IoTSimulatordbContext>(null);
And therefore you will need to run update-database manually to update the model (you can run this via package manager console). If you have any data in your tables it is likely that the migration will fail due to the possibility of losing data, in that case you will need to either delete all data from the tables first or make a custom migration script to handle copying the data first. As this seems like a test it may be better to restart the migration project with the pluralisation off from the beginning.
You can add a DataAnnotation to describe the Schema and Table name to your Table class such as this;
[Table("Device", Schema = "MySchema")]
This will give you more control over the naming.
I have a site. using COde first. My add-migration command producted following code.
public partial class StudentEntity : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Student",
c => new
{
id = c.Int( nullable: false, identity: true),
name = c.String(),
})
.PrimaryKey(t => t.id);
}
Now I want to deploy my site so when site runs the first time I want the Student table to get generated in DB(SQL server).
Right now when I run the site it does not create any table. How can I do this? I dont want any seed data to initialize with
My db context class
public partial class flagen:DbContext
{
public flagen() : base("name=cf2")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
//old entity
public virtual DbSet<flag> flags { get; set; }
//new entity
public virtual DbSet<Student> students { get; set; }
}
Then I tried to use Context so table get created. It throws error "The model backing the 'flagen' context has changed since the database was created. Consider using Code First Migrations to update the database "
The I added following two lines to dbcontext class
Database.SetInitializer<flagen>(null);
base.OnModelCreating(modelBuilder);
now it says "invalid object name students"
any solution that works?
One solution could be to define a Initializer that will migrate your database to last existing migration you added. Therefore all tables will be created and the Seed method of the Configuration will be executed too - you could use it for seeding data.
With the following example your database will be updated to last existing migration (and therefore creates all tables) on first initialization of the data context. (var dbContext = new MyDatabaseContext())
In my opinion a much cleaner way than to use AutomaticMigrationsEnabled = true that you could check out too. ;)
As mentioned here is an example that will use the MigrateDatabaseToLatestVersion initializer with the defined behavior.
public partial class MyDatabaseContext : DbContext
{
public virtual DbSet<Student> students { get; set; }
public MyDatabaseContext() : base("MyDatabaseContextConnectionString")
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDatabaseContext, Migrations.Configuration>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// here we want to define the entities structure
}
}
You will find some more information about the initializer itself here (MSDN
- MigrateDatabaseToLatestVersion) and here (Entity Framework Tutorial - Code-First Tutorials - Automated Migration) is another example with some more background information and examples.
The answer of this question is to use T4 templates. After searching the web I got the answer that nobody could on SO. Shame...
https://archive.codeplex.com/?p=t4dacfx2tsql
Objective:
Use EF to enter in data from a POST request from an API. The POST request will contain an "ID", that will map the connection string to an enum, which will have the same name connection string name as it has in the Web.config. Create the "base" context object and add the object to the appropriate table.
Note:
I know I can do this using SqlCommand, but I wanted to take a crack at it using entity framework instead, but I hit a wall.
I've used EF for years, but I wanted to make this POST method as global as I can get it. This API will accept numerous requests from numerous different web sites, but all will use the same model. Each websites POST will go into a different database (that's how they are requesting it).
The problem that I foresee is, each "entity" knows what tables it contains. So when one types context.TABLE.Add(object), EF understands that you want to put this "Car" object in the "Car" table (obviously).
Can this be done using a "global" entity???
public class DbConnectionNames
{
public enum DbConnectionStringNames
{
SocHopeHcpEntities = 1, // "1" is passed into the POST to map
XXXXEntities = 2,
......
}
}
<add name="SocHopeHcpEntities" connectionString=".........." />
<add name="XXXXEntities" connectionString=".........." />
.....
var professional = new Professional
{
....
....
};
string connStringContext = Enum.GetName(typeof(DbConnectionNames.DbConnectionStringNames), model.FormId).ToString();
string connectionString = ConfigurationManager.ConnectionStrings[connStringContext].ConnectionString;
using (var context = new ObjectContext(connectionString))
{
context.Professionals.Add(professional); // obviously this doesn't work
context.SaveChanges();
}
EDIT:
My EF is NOT using POCO, but is already based off a DB to begin with. There could be XX number of different databases, all holding the same similar table. I already have a YYYEntities.Context.cs file auto-generated that inherits from DbContext:
public partial class SocHopeHcpEntities : DbContext
{
public SocHopeHcpEntities()
: base("name=SocHopeHcpEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<AreasOfWork> AreasOfWorks { get; set; }
public virtual DbSet<Professional> Professionals { get; set; }
}
You still need a context that understands what a Professional is. For example:
public class ProfessionalContext : DbContext
{
public ProfessionalContext(string connectionString)
: base(connectionString)
{
//This line is optional but it prevents initialising the database
//every time you connect to a new database
Database.SetInitializer<ProfessionalContext>(null);
}
public DbSet<Professional> Professionals { get; set; }
}
And use it like this:
using (var context = new ProfessionalContext(connectionString))
{
context.Professionals.Add(professional);
context.SaveChanges();
}
DavidG's answer showed you how to pass a connection string to a strongly typed context that knows the entity types you are dealing with. That context inherits from DbContext which you can use directly as illustrated below.
It is worth noting the generic way that does not involve a context 'object' that is specific to your database.
For example see how ObjectContext is used here:
System.Data.Objects.ObjectContext oc = new System.Data.Objects.ObjectContext("connection string");
oc.AddObject("ProfessionalsTable", professional);
Another example is using DbContext:
System.Data.Entity.DbContext dbc = new DbContext("");
dbc.Set(typeof(Professional)).Add(professional);
The generic approach is better if you also do not know which table you want to insert to, so you can also make the object that you want to insert dynamic.
I am trying to run a demo app to do a POC on Linq-to-Sqlite. I'm using the latest System.Data.Sqlite NuGet package and .Net Framework 4.5 to create sample console application which will only create the database file initially. The code simply creates an object of Movie class and adds it to the DbSet property on the DbContext class. However, on SaveChanges(), i get a System.Data.Entity.Infrastructure.DbUpdateException with the message "no such table: Movie". Below is my code:
if (!File.Exists(_databaseFilePath))
SQLiteConnection.CreateFile(_databaseFilePath);
using (var dbContext = new MovieAppContext())
{
dbContext.Movies.Add(new Movie(1, "Titanic", 7.5));
var retVal = dbContext.SaveChanges();
}
public class MovieAppContext : DbContext
{
public MovieAppContext():base("MovieAppConStr")
{
}
public MovieAppContext(string connectionString)
: base(connectionString)
{ }
public DbSet<Movie> Movies { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Chinook Database does not pluralize table names
modelBuilder.Conventions
.Remove<PluralizingTableNameConvention>();
}
}
EDIT: So the question is, just like Linq-to-Sql, does Linq-to-Sqlite provider allow us to create tables in the database equivalent to the models created using the code-first approach ?
Entity Framework Code First with SQLite only Works with an existing database, so no. There are alternative EF providers for sqlite that do support database creation with Code First... Devart for example