I've followed Adam's answer here and the Entity Framework now works and the Seed() method also works.
But when I try to access the database like this:
public User FindUserByID(int id)
{
return (from item in this.Users
where item.ID == id
select item).SingleOrDefault();
}
.............................................................................
// GET: /Main/
public ActionResult Index(int? id)
{
var db = UserDataBaseDB.Create();
if (!id.HasValue)
id = 0;
return View(db.FindUserByID(id.Value));
}
It throws an exception at return (from item in this.Users stating:
Exception Details: System.Data.SqlClient.SqlException: Invalid object name 'dbo.BaseCs'.
I've tried replacing it with:
return this.Users.ElementAt(id); but then it throws this exception.
LINQ to Entities does not recognize the method 'MySiteCreator.Models.User ElementAt[User](System.Linq.IQueryable1[MySiteCreator.Models.User], Int32)' method, and this method cannot be translated into a store expression.`
Can anyone help me?
Exception Details: System.Data.SqlClient.SqlException: Invalid object name 'dbo.BaseCs'
This error means that EF is translating your LINQ into a sql statement that uses an object (most likely a table) named dbo.BaseCs, which does not exist in the database.
Check your database and verify whether that table exists, or that you should be using a different table name. Also, if you could post a link to the tutorial you are following, it would help to follow along with what you are doing.
It is most likely a mismatch between the model class name and the table name as mentioned by 'adrift'. Make these the same or use the example below for when you want to keep the model class name different from the table name (that I did for OAuthMembership). Note that the model class name is OAuthMembership whereas the table name is webpages_OAuthMembership.
Either provide a table attribute to the Model:
[Table("webpages_OAuthMembership")]
public class OAuthMembership
OR provide the mapping by overriding DBContext OnModelCreating:
class webpages_OAuthMembershipEntities : DbContext
{
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
var config = modelBuilder.Entity<OAuthMembership>();
config.ToTable( "webpages_OAuthMembership" );
}
public DbSet<OAuthMembership> OAuthMemberships { get; set; }
}
If you are providing mappings like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ClassificationMap());
modelBuilder.Configurations.Add(new CompanyMap());
modelBuilder.Configurations.Add(new GroupMap());
....
}
Remember to add the map for BaseCs.
You won't get a compile error if it is missing. But you will get a runtime error when you use the entity.
It might be an issue about pluralizing of table names. You can turn off this convention using the snippet below.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
If everything is fine with your ConnectionString check your DbSet collection name in you db context file. If that and database table names aren't matching you will also get this error.
So, for example, Categories, Products
public class ProductContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
should match with actual database table names:
EF is looking for a table named dbo.BaseCs. Might be an entity name pluralizing issue. Check out this link.
EDIT: Updated link.
My fix was as simple as making sure the correct connection string was in ALL appsettings.json files, not just the default one.
Instead of
modelBuilder.Entity<BaseCs>().ToTable("dbo.BaseCs");
Try:
modelBuilder.Entity<BaseCs>().ToTable("BaseCs");
even if your table name is dbo.BaseCs
For what it is worth, I wanted to mention that in my case, the problem was coming from an AFTER INSERT Trigger!
These are not super visible so you might be searching for a while!
I don't know if is the case,
If you create a migration before adding a DbSet your sql table will have a name of your model, generally in singular form or by convention we name DbSet using plural form.
So try to verifiy if your DbSet name have a same name as your Table. If not try to alter configuration.
Most probably the translated SQL statement can't find the table name.
In my case, the table was assigned to a different schema. So, in the model you should enter the schema definition for the table like this:
[Table("TableName", Schema = "SchemaName")]
public class TableName
{
}
You have to define both the schema and the table in two different places.
the context defines the schema
public class BContext : DbContext
{
public BContext(DbContextOptions<BContext> options) : base(options)
{
}
public DbSet<PriorityOverride> PriorityOverrides { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasDefaultSchema("My.Schema");
builder.ApplyConfiguration(new OverrideConfiguration());
}
}
and for each table
class PriorityOverrideConfiguration : IEntityTypeConfiguration<PriorityOverride>
{
public void Configure(EntityTypeBuilder<PriorityOverride> builder)
{
builder.ToTable("PriorityOverrides");
...
}
}
In EF (Core) configuration (both data annotations and fluent API), the table name is separated from the schema.
Remove the "dbo." from the table name and use the ToTable overload with name and schema arguments:
.ToTable("MyUsers", "dbo");
Or taking into account that dbo is the default schema (if not configured differently), simply:
.ToTable("MyUsers");
As it is currently, it considers table dbo.dbo.MyUsers which of course does not exist.
The solution is very simple.
Just run the migration. Make sure you have the migrations folder with the code. Then on the Configure method of startup, put this code first in you method body:
using (IServiceScope scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
scope.ServiceProvider.GetService<FRContext>().Database.Migrate();
}
This update the database, but its base in the migrations folder. I created the database, but if it does not find the migration folder with the files, it will create the database without tables, and you app will break at runtime.
Use table annotation in your class and use the name same as the name of view or table in the database
[Table("tbl_Sample")]
public class tblSample
{
//.........
}
In the context definition, define only two DbSet contexts per context class.
Wrong DB configuration in my tests while I was looking at the configuration from the project being tested.
In my case, I put the wrong ConnectionString name in connectionString Configuration in Startup.cs, Your connectionstring name in startup.cs and appsettings.json must be the same.
In appsettings.json:
In startup.cs:
Thats why when i made query using this context, it found no connectionstring from the appsettings when there was a wrong name. Consequently, it results Invalid Object Name 'a db table name'.
Related
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'm using Entity Framework to insert data into 2 different databases. There are a few columns that are present in one of the databases but not the other. Their data types are not nullable (int and float).
I don't use these columns (when they are present) in my code. Meaning I only insert 0 as the data for them but I can't send null obviously.
Is there a way for me to insert data with ease without creating 2 different versions of my app for these? Ideally I'd like to just have one model with something like an attribute that says insert 0 in this column if it's available.
If your application runs only against one database, then you can just use an IF statement in your OnModelCreating that uses the Fluent API to .Ignore() the missing properties.
public class MyDbContextWithMissingColumns: MyDbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (myConfig.UseDatabaseWithoutSomeProperties)
{
modelBuilder.Entity<Foo>().Ignore(f => f.SomeProperty);
}
base.OnModelCreating(modelBuilder);
}
}
If a single instance of your application connects to both databases, then you have to use separate DbContext subtype, as OnModelCreating only runs for the first instance of a DbContext type in an AppDomain.
EG:
public class MyDbContextWithMissingColumns: MyDbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>().Ignore(f => f.SomeProperty);
base.OnModelCreating(modelBuilder);
}
}
In the repository for the database with the restricted fields create the entity:
public class MyClass
{
int MyCommonClassID {get; set;}
string Name {get; set;}
[NotMapped]
string PhoneNumber {get; set;}
}
Where the attribute [NotMapped]. is used that field will not appear in the database but you can use it everywhere else. That wat you determine what gets written at the lowest level and your application doesn't care.
I have class with the following struct:
public class student
{
public int Id {get;set;}
public string name {get;set;}
}
I use the following configuration on model creation to match table column with class in the database based on parameter for example I have ,
16_student,17_student,18_student..... all these tables match the student class
public class studentConfiguration : EntityTypeConfiguration<Models.student>
{
public studentConfiguration (string SchoolId)
{
this.ToTable(SchoolId + "_student");
}
}
The previous function work fine with existing Tables , but how i can force the EF to create new table based on new parameter
in the other word i need if i pass parameter not exist let's say schoolId = 55 new table should be created with the name 55_student if not exist
I Enable Automatic migration now and the tables created successfully when it was not exists but the problem now when I add new school with id 56 the previous tables deleted so i can only add one table each time
is there any where to prevent migration from call delete for these tables just create ??
If I understand correctly, you have a database table with a table that has a name that is composed from several values of variables. You also hava a DbSet<TEntity> in your DbContext, and you want to tell entity framework that this DbSet is modeled in your database in a table that has this composed name.
Seeing your advanced usage of class EntityTypeConfiguration I assume that you know that this is done in function DbContext.OnModelCreating
The raison d`ĂȘtre of DbContext is to connect your entity framework classes to the actual database that your classes use. The proper way to model your database would be in this class.
Apparently your override of 'DbContext.OnModelCreating' creates a StudentConfiguration object. This object will do the actual configuring of the Student entity.
You probably will do this for several entities of your database. All these configurations will need similar information. One of them is the name of the table, others could be the maximum length of certain strings, or the precision of decimals etc.
The proper way to do this, is to give your StudentConfiguration an object (o an interface) that contains this information. The whole idea is similar to the factory design pattern:
interface ISchoolRequirements
{
public string StudentTableName {get;}
... // other items that differ per school
}
class MySchoolRequirements : ISchooRequirements
{
... // properties needed to create a StudentTableName
// the function that composes the StudentTableName from the properties
private string CreateStudentTableName() {...}
// implementation of ISchoolRequirements
public string StudentTableName {get{return this.CreateStudentTableName(); }
}
public class studentConfiguration : EntityTypeConfiguration<Models.student>
{
public studentConfiguration (ISchoolRequirement schoolRequirements)
{
this.ToTable(schoolRequirements.StudentTableName);
... // other configuration items
}
}
Your DbContext with OnModelCreating:
class MyDbContext : DbContext
{
ISchoolRequirements SchoolRequirements {get; set;}
public DbSet<Student> Students {get; set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// if no school requirements set, use default school requirements:
ISchoolRequirements schoolRequirement = this.SchoolRequirements ??
CreateDefaultSchoolRequirements();
// create the configurations:
modelBuilder.Configurations.Add(new StudentConfiguration(schoolRequirements));
modelBuilder.Configurations.Add(new TeacherConfiguration(schoolRequirements));
modelBuilder.Configurations.Add(new ClassRoomConfigurations(schoolRequirments));
... // etc
}
}
The advantage is that the creator of your DbContext has full control on the naming of the tables, the maximum size of certain strings, the precision of decimals, the type of DateTime etc. If the user of your DbContext does not need this control, some default configuration is used. You could even decide to read this default configuration from a configuration file
This question already has answers here:
The entity type 'Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin<string>' requires a key to be defined
(4 answers)
Closed 4 years ago.
i am using dotnet core 1.1 on linux, and i am having issues when i want to split up the identityContext from my regular dbContext, whenever i run the following line in my startup.cs --> configure:
//... some other services
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetService<ApplicationDbContext>().Database.Migrate();
//running other database.migrations here + seeding data. But it is the line above that causes problems
So this line throws the exception: The entity type 'IdentityUserLogin' requires a primary key to be defined
I simply don't understand this, why is it my job to give the IdentityUserLogin a primary key??, it is a 3rd party class and i haven't even touched it. I have the following simple setup:
namespace EsportshubApi.Models
{
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public ApplicationDbContext()
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
}
And the applicationUser:
namespace EsportshubApi.Models.Entities
{
public class ApplicationUser : IdentityUser
{
public ApplicationUser() { }
public static ApplicationUserBuilder Builder()
{
return new ApplicationUserBuilder(new ApplicationUser());
}
public int AccountId { get; set; }
public Guid AccountGuid { get; set; }
public string Salt { get; set; }
public bool Verified { get; set; }
public string Checksum { get; set; }
public string Password { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
}
}
In my startup i am configuring the identity framework the following way:
configureServices:
services.AddEntityFrameworkSqlServer().AddMySQL().AddDbContext<ApplicationDbContext>(options =>
options.UseMySQL(config["ConnectionStrings:DefaultConnection"]));
And
Configure:
app.UseIdentity();
My project is opensourced at : my github repo
if that helps.
I have tried a lot of things. The two most promising was deriving all of the classes used in this generic show, and passing them in explicitly, tried to change all of their keys to ints etc. And that gave the exact same error just with int instead of string. The other way i tried was to do the following inside of OnModelCreating to give IdentityUserLogin a primary key by e.g :
modelBuilder.Entity<IdentityUserLogin<int>>()
.Property(login => login.UserId)
.ForMySQLHasColumnType("PK")
.UseSqlServerIdentityColumn()
.UseMySQLAutoIncrementColumn("AI");
As you can see, this was back when i had UserId as a integer, but i am not even sure if the UserId should be its primaryKey. I can get other errors instead of this one, that says
IdentityUserLogin is part of a hierarchy, and it has no discriminator values
But if I had discriminator values it eventually just goes back to this error. The weirdest part i think is that i have the EXACT same implementation as the UnicornStore github example, that uses a bit of the identity framework as well .... So i really need your help guys. Can reproduce this error by downloading the project, copying the default.appsettings.json into appsettings.json, put in a valid connectionstring, dotnet restore, run with dotnet run --environment Development.
I even tried to change out the implementation to use a MSSQL database instead of MySQL, but that gave the exact same error.
keys of Identity tables are mapped in OnModelCreating method of IdentityDbContext and if this method is not called, you will end up getting the error that you got.
All you need to do is call.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
The original answer (just copied for other's reference just in case) here
Okay. So i will try to answer my own question, because i did get past it. Its still possible to follow the github link in the OP, and see the project i got the error in.
Mainly what was wrong, was that i thouth i got this error trying to migrate the ApplicationDbContext : IDentityContext but actually the error was thrown based on my other dbContext in the application, when i tried to run the migration on that one. I am still a little unaware as to why the other DbContext picked up on these Identity entities which i had not referred to anywhere, i think it's odd that a dbcontext seems to know something about entities not mentioned in the OnModelCreating method. Anyway - when i found out that it wasn't the IdentityDbContext that something was wrong with, i simply added the following in the OnModelCreating of the context that threw the error:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Ignore <IdentityUserLogin<string>>();
modelBuilder.Ignore <IdentityUserRole<string>>();
modelBuilder.Ignore<IdentityUserClaim<string>>();
modelBuilder.Ignore<IdentityUserToken<string>>();
modelBuilder.Ignore<IdentityUser<string>>();
modelBuilder.Ignore<ApplicationUser>();
So ... i am still wondering why my context is picking up on these entities without having anything to do with them, and i am pretty worried that each time i add a context i have to exclude models in contrary to including them.
I had a similar issue relating to your initial problem where
The entity type 'IdentityUserLogin' requires a primary key to
be defined.
And while I think your solution to ignore entities seems to work, I just wanted to provide another solution for those who actually do want to assign a primary key to each entity. The problem is that whenever you create an entity, the DbContext will want keep track of the primary key for each - thus, you'd have to assign it.
See my example below, where Project and Target are my entities, and I've assigned it each a property I would like to use as the primary key for each entity.
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Project>().HasKey(m => m.ProjectPath);
builder.Entity<Target>().HasKey(m => m.Guid);
base.OnModelCreating(builder);
}
After you've identified and assigned which property should be designated as the primary key for that entity, the error will go away.
I have a project built using EF code first. It also uses forms authentication. Until recently the membership database and the application database were being developed separately, but I want to combine them into one database for simplicity.
One of the classes in my code first model is called "Application" so the EF-generated table is called "Applications" which conflicts with a membership table of the same name. This is an example of my current context:
public partial class ExampleContext : DbContext
{
public DbSet<Application> Applications { get; set; }
public DbSet<Status> StatusTypes { get; set; } // notice the name of the property vs the name of the class
}
I thought the table names were based on the names of the properties in the context, because it was generating a table named StatusTypes for all of the Status objects. But if I rename the Applications property to something like MyApplications it is still generating a table named Applications. So clearly it's not just the name of the property and I'm missing something.
My question: how do I get EF to name this table differently?
Couldn't you use the configuration class to do something like this:
public class ApplicationConfiguration : EntityTypeConfiguration<Application>
{
public ClientConfiguration()
{
ToTable("SpecialApplication");
}
}
Then in your context override OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ApplicationConfiguration());
}
This should then force your table to be named SpecialApplication and avoid the conflict
By default, Entity framework code first will generate pluralized names for tables when it builds the db from the model classes. You can override the OnModelCreating method of your db context class specify a different name for the table.
public class YourDBCOntext:DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Applications>().ToTable("MYApplications");
}
}
You can do this globally also so that none of the tables will have pluralized names.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTaleNameConvention>();
}
}
I just renamed the class and it worked. Easiest solution for now.