We have a Data library they have built it with CodeFirst.
Now I ran a SQL command and added a new table to that database.
But Now I want to also see its generated object class, its DBContext definitions ,etc.. in the code first code so I can use them in my LINQ queries.
So what I did was following number 3 method from this MSDN page:
https://msdn.microsoft.com/en-us/library/jj200620.aspx
But it didn't do it right. For example it did not add any definition for this new table to DBContext.cs file, for example all my other tables that used to be there are defined like this:
DbSet<Zipcode> Zipcodes { get; set; }
But it has not added anything for me.
What is the correct way to do this?
I'm unaware of a way to simply add a new table and have it 'plug-n-play' with your existing model without manual work. The two options I know of are:
Rebuild the model using Code First from DB and include your added table
Manually create the table as a class and add the DbSet and entity in the OnModelCreating method in your model
Code First from Database only works when you already have a database. If you want to add a new table, you will have to start using Code-First(alone), that means: add the entity Zipcode to the model, DbSet to the DbContext and after that when you compile it will generate de table in the database.
Related
I am working on an asp.net mvc application using C#. For database, I am using Entity Framework and code-first approach. I have an sql view that I need to execute and store its result in a list. I know how to query data from DB using ApplicationDbContext, stored procedure and inline queries. But now I want to do the same using a view.
The view looks like this
CREATE VIEW [dbo].[GenresView]
AS SELECT * FROM Genres
I have a Genre class that has the same properties that the view will return.
Steps to handle a view:
Create a GenresView class with properties mapped to view columns. You can use EF features like virtual properties and ForeignKey annotations to be able to load entities related to the view in your queries.
Add the created entity as a new property DbSet GenresView to your database context.
Add new migration using Package Manager Console and add migration command.
As you can notice, the generated migration contains statements for creating a new table for the GenresView in the Up() method. Delete this code and replace it with Sql(#"CREATE VIEW dbo.GenresView AS SELECT * FROM Genres") statement.
IMPORTANT!!! It is better to define all fields which you want to get instead of * .
You should also replace the code in the Down() method to be able to revert the migrations properly. Its code should contain call to Sql(#"DROP VIEW dbo.GenresView").
Update the database.
Now you can use the new entity in your LINQ statements as it were a regular table (e.g. dbContext.GenresView.).
I came across this related question: How can I generate DDL scripts from Entity Framework 4.3 Code-First Model?
But this doesn't appear to answer the question of when a Code First application actually checks the existence/correctness of the DB and modifies it if necessary. Is it at run-time or build time? Assuming it's at run-time is it at start-up or when you create the DbContext or at the last possible moment e.g. when you try to write/read the DB table(s) it checks they exist on a case-by-case basis?
It is ceated at rutime the first time you access an entity, ie,
using (var db = new MyDBContext())
{
var items = db.MyObj.Count() // <- Here it is created!
}
There are some flavors on how, like if you set the creating strategy to CreateDatabaseIfNotExists, DropCreateDatabaseAlways, Etc. Please give this a look:
http://www.entityframeworktutorial.net/code-first/database-initialization-strategy-in-code-first.aspx
The column Model in the table __MigrationHistory is serialized and gzipped(base64) version of your EDMX. In code first the column Model is generated by Add-Migration and stored in the second part of the migration partial class and in the database when the database is created as binary stream varbinary(max).
When the database initializer (Database.SetInitializer) is called, then EF generate from the classes on the fly(Runtime) the current Entity Data Model(EDMX). The generated model will be serialized, zipped(base64) and finally compare it with the stored Model of the migration history table.
The comparison happens before the DbContext is created and, if the two Models(binary streams) are not identical then you will get a compatibility exception.
I had something like:
class Person
string CarModel
which in terms of database got translated to MyClass table with 'MyProperty' string column.
Now I have:
class Person
string CarId
class Car
int Id
string Model
Which EF translates to two tables: MyClass and MyNewClass, and there is Car.CarId -> pointing to Car.Id. So far so good.
I will manually take care of populating the Car table with the items that were in the Person.CarModel column. But question is: how do I migrate my data? I want the Person.CarId to point to the correct Car.Id record. I am thinking something like:
UPDATE [dbo].[Person]
SET [CarId] = cars.Id
FROM [dbo].[Cars] cars
WHERE cars.Model = [dbo].[Cars].CarModel
I am doing that between the Adding of the new column (CarId) and the drop of the old column (CarModel) from the table. However, the SQL server complains 'CarId column does not exist'. I guess it has something to do with the change being transactional.
What is the correct approach to this? I am using scripts (i.e. I am deleting my Migrations folder after I generate the .sql out of it)
I believe the best way is:
Remove old CarModel string from the model and add new Car entity to your Person, but in migration behind this instead of deleting a CarModel column rename it to [_Stale_CarModel] (naming is just for example).
Run your manual data migration script over the database, verify that data is migrated correctly - ids are set for rows that have [_Stale_CarModel] set and values are correct. You can either manually add an EF migration with your data migration code inside, or do it on your own if you need to do verification script for your data before commiting actual migrated data OR if your migration takes more than default timeout.
Create a migration for cleaning up your DB schema (EF will create empty migration for this step) and manually write DropColumn("Person", "[_Stale_CarModel]")
I have a mvc 4 application which is entity framework database first based. Therefore lots of the classes are generated based on database tables via EF.
Currently, I created a method to retrive data from a table and display them in a dropdownlist, which works fine. However, I am thinking to modify that method to a generic type method, and passing the class type as the method parameter, and I would like c# code to find the mapping table in the database and retrive the data.
Following is my modified method
Thanks for your helps!
public static SelectList FromDbTableToSelectList<T>() where T: class
{
var db = new TableEntities();
//find the mapping database table
Dictionary<Guid, string> dic = db.MappingTable.ToDictionary(v => v.tableColumn1, v => v.tableColumn2);
return new SelectList(dic, "Key", "Value");
}
I don't understand your what your code does. However, there is a trick to find mapping table name (Entity Set Name in EF glossary) of an entity.
Suppose that you have a table in your db named Products. If you create your model with the Pluralize and singularize option checked, EF will create an entity class named Product.
Then, whenever you perform a query, EF naming convention thinks that your table name is dbo.Products. This is a general rule - in fact a naming convention.
From the other hand, if you uncheck the Pluralize and Singularize option, EF creates an entity class named Products for you and in this case, the class an the table have same names.
So, according to the selection of P&S option, you can infer table names from entity names and you don't need any code for it...
I'm using entity framework code first to create my tables. Please note - create the tables, not the DB, since I'm working on a hosted environment and I don't have a user that is allowed to create db's.
Committing a DB update works fine, but retrieving data gives the exception:
Exception Details: System.Data.SqlClient.SqlException: Invalid object name 'dbo.EventHosts'.
I've read that it happens because I'm not using EF Code First to create the DB. That's fine, but how do I elegantly solve this?
All the generated tables do not have a prefix like dbo. A solution like this doesn't work, and isn't elegant at all:
[Table("EventHosts", Schema = "")]
Ok, for me issue was that I had a table called dbo.UserState and in C# EF was trying to access dbo.UserStates because of pluralization.
The solution was to put Table attribute above class and specify the exact table name:
[Table("UserState")]
public class UserState
{
[Key]
public int UserId { get; set; }
}
To answer your first question: use the schema created for you by your hosting provider.
To answer your second question: No there is currently no direct way to change the default schema globally because you cannot modify existing conventions or create new conventions. You can try to hack it.
For example you can override OnModelCreating and use reflection to get all DbSet<> properties declared in your context. Than you can just use simple loop on these properties and create ToTable mapping call with name of the property as table name and your custom schema. It will require some playing with reflection to make this work.
Alternatively you can try to do some reusable approach by implementing custom conventions. You can find many different articles about using your own conventions with EF. Some examples:
Custom Conventions in Entity Framework Code First v 4.1
Conventions in Entity Framework 4.1 Final
My high level untested idea is following same principle and create assembly level attribute which will be processed by the convention mechanism and applied on all your entities.
Try to set default schema name to 'dbo' in SQL SERVER.
http://msdn.microsoft.com/en-us/library/ms173423.aspx
On of the reason for this error is the table named "EventHosts" may not Exist or that table is renamed to some other name please check with that..
https://stackoverflow.com/a/12808316/3069271
I had same issue, it was pluralize problem between mapping and db.