Invalid Object Name error when creating database with EF Code First - entity-framework-core

Hello i am developing a database using EF Core Code First.I keep getting this error when generating the database :
Microsoft.EntityFrameworkCore.DbUpdateException: 'An error occurred
while updating the entries. See the inner exception for details.'
InnerException {"Invalid object name 'Parents'."} System.Exception {Microsoft.Data.SqlClient.SqlException}
From what i have read it seems i can not create the database because the tables are somehow pluralized.
I have searched for solutions including this SO thread and tried the solutions to no avail. The one that i have not tried is the RemovePluralization method because
I do not have this Conventions field in my ModelBuilder and i can not find the package containing it.
Context and Models
public class Parent {
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
public Parent() {
this.Children = new List<Child>();
}
}
public class Child {
public int ID { get; set; }
public string Name { get; set; }
public Parent Parent { get; set; }
public int ParentId { get; set; }
}
public class MyContext : DbContext {
public virtual DbSet<Parent> Parents { get; set; }
public virtual DbSet<Child> Children { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Child>()
.HasKey(x => x.ID);
modelBuilder.Entity<Parent>()
.HasKey(x => x.ID);
modelBuilder.Entity<Parent>()
.HasMany(x => x.Children)
.WithOne(k=>k.Parent)
.HasForeignKey(t => t.ParentId);
}
public MyContext(DbContextOptions options):base(options) {
this.Database.EnsureCreated();
this.Database.Migrate(); //i have tried this too
}
}
Usage
var optionsBuilder = new DbContextOptionsBuilder<MyContext>();
optionsBuilder.UseSqlServer(connectionString);
MyContext context = new MyContext(optionsBuilder.Options);
Parent parent = new Parent() { Name = "Parentino" };
context.Parents.Add(parent);
await context.SaveChangesAsync(); //crashes with before mentioned error
I have also tried to set the table names in my OnModelCreating overload this:
modelBuilder.Entity<Parent>().ToTable("parent");
or directly with [Table("name")] attribute over my Model classes to no avail.
Could someone help me out and tell me why i can't generate the database ?

Works fine for me
program.sc
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static async Task Main(string[] args)
{
string connectionString = "Server=(localdb)\\MSSQLLocalDB;Initial Catalog=test;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
var optionsBuilder = new DbContextOptionsBuilder<MyContext>();
optionsBuilder.UseSqlServer(connectionString);
MyContext context = new MyContext(optionsBuilder.Options);
Parent parent = new Parent() { Name = "Parentino" };
context.Parents.Add(parent);
await context.SaveChangesAsync(); //crashes with before mentioned error }
}
}
public class Parent
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
public Parent()
{
this.Children = new List<Child>();
}
}
public class Child
{
public int ID { get; set; }
public string Name { get; set; }
public Parent Parent { get; set; }
public int ParentId { get; set; }
}
public class MyContext : DbContext
{
public virtual DbSet<Parent> Parents { get; set; }
public virtual DbSet<Child> Children { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Child>()
.HasKey(x => x.ID);
modelBuilder.Entity<Parent>()
.HasKey(x => x.ID);
modelBuilder.Entity<Parent>()
.HasMany(x => x.Children)
.WithOne(k => k.Parent)
.HasForeignKey(t => t.ParentId);
}
public MyContext(DbContextOptions options) : base(options)
{
this.Database.EnsureCreated();
this.Database.Migrate(); //i have tried this too
}
}
}
ConsoleApp1.csproj
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

Related

Unable to create an object of type 'AppContext'. Npgsql + EFCore

How to resolve my "HelloEFCore" .NET Core console app exception? I use Npgsql Entity Framework Core Provider (https://www.npgsql.org/efcore/)
Unable to create an object of type 'AppContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
It occurs when I try to do initial migration
dotnet ef migrations add CreateDatabase
Code that I'm working with:
Program.cs
class Program
{
static void Main(string[] args)
{
AppContext a = new AppContext("Server=127.0.0.1; port=5432; user_id=postgres; password=root; database=db; pooling=true");
}
}
Product.cs
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public int BrandId { get; set; }
public Brand Brand { get; set; }
}
Brand.cs
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
public List<Product> Products { get; set; } = new List<Product>();
}
AppContext.cs
public class AppContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Brand> Brands { get; set; }
private readonly string _connectionString;
public AppContext(string connectionString)
{
_connectionString = connectionString ??
throw new ArgumentException("connectionString is empty.");
}
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseNpgsql(_connectionString);
}
}
efstart.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.8" />
<PackageReference Include="Npgsql" Version="4.1.3"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.3"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.4"/>
</ItemGroup>
</Project>
Application compiles well. I use pgAdmin on Ubuntu 20.04.
You need to implement IDesignTimeDbContextFactory interface to make your solution work without any problems.
public class AppContext Factory : IDesignTimeDbContextFactory< AppContext>
{
public AppContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<AppContext>();
builder.UseNpgsql(connectionString);
return new DataContext(builder.Options);
}
}

EF6 Code First - Multiple one-to-many and same entity

I have an entity model that contains multiple definitions to another entity. I can get one definition to work, but not both.
public class Inspection : Entity<int>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InspectionId { get; set; }
[ForeignKey("Report")]
public int ReportId { get; set; }
public virtual Report Report { get; set; }
....
public virtual ICollection<ResidentialDescriptionItem> ResidentialDescriptionItems { get; set; }
public virtual ICollection<ResidentialDescriptionItem> ResidentialOtherDescriptionItems { get; set; }
}
public class ResidentialDescriptionItem : Entity<int>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ResidentialDescriptionItemId { get; set; }
public int InspectionId { get; set; }
[ForeignKey("InspectionId")]
public virtual Inspection Inspection { get; set; }
//public int Inspection1Id { get; set; }
//[ForeignKey("Inspection1Id")]
//public virtual Inspection Inspection1 { get; set; }
}
I've made numerous attempts with that second index and received just as many different errors. The above configuration results in
Unable to determine the principal end of the
'MySolution.EntityFramework.ResidentialDescriptionItem_Inspection'
relationship. Multiple added entities may have the same primary key.
I would like to maintain a full configuration with navigation on both sides. How do I do this using Code First and Annotations?
I don't think it is possible to implement such complex relationship with annotations, but here is a demo, how you would need to override your DbContext.OnModelCreating
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
namespace ConsoleApp3
{
public class Parent
{
[Key]
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
public virtual ICollection<Child> OtherChildren { get; set; }
}
public class Child
{
[Key]
public int Id { get; set; }
[ForeignKey("Parent")]
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual Parent Parent { get; set; }
[ForeignKey("OtherParent")]
public int? OtherParentId { get; set; }
[ForeignKey("OtherParentId")]
public virtual Parent OtherParent { get; set; }
}
public class MyDbContext : DbContext
{
public MyDbContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
}
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Parent>()
.HasMany(x => x.Children)
.WithOptional(x => x.Parent);
modelBuilder.Entity<Parent>()
.HasMany(x => x.OtherChildren)
.WithOptional(x => x.OtherParent);
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyDbContext>());
var ctx = new MyDbContext("Data Source=DESKTOP-5PVJ0I5;Database=test1;Integrated Security=true");
var parent = ctx.Parents.Add(new Parent());
ctx.Children.Add(new Child()
{
OtherParent = parent
});
ctx.Children.Add(new Child()
{
Parent = parent
});
ctx.SaveChanges();
parent = ctx.Parents
.Include(x => x.Children)
.Include(x => x.OtherChildren)
.FirstOrDefault();
}
}
}

Can not set up one to many relationship with EF fluent API

I am trying to configure a one to many relationship using EF Core via fluent api and i keep getting the following error :
The expression 'x => x.parent' is not a valid property expression. The
expression should represent a simple property access: 't =>
t.MyProperty'. (Parameter 'propertyAccessExpression')'
Model(s)
public class Parent {
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child {
public int ID { get; set; }
public string Name { get; set; }
public Parent parent;
public int ParentId { get; set; }
}
Context
public class MyContext : DbContext {
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Child>().HasKey(x => x.ID);
modelBuilder.Entity<Parent>().HasKey(x => x.ID);
modelBuilder.Entity<Child>()
.HasOne(x => x.parent)
.WithMany(y => y.Children)
.HasForeignKey(t => t.ParentId);
}
public MyContext(DbContextOptions options):base(options) { }
}
Usage
static async Task Main(string[] args)
{
string connectionString = "[someconnectionstring]"
var optionsBuilder = new DbContextOptionsBuilder<MyContext>();
optionsBuilder.UseSqlServer(connectionString);
MyContext context = new MyContext(optionsBuilder.Options);
await context.Parents.AddAsync(new Parent {
Name = "myparent",
Children = new List<Child>() {
new Child { Name = "Child1" },
new Child { Name = "Child2" } }
}); //i am getting the error here
await context.SaveChangesAsync();
}
parent in Child class is a field. It should be public property. Please see for more information https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/fluent/types-and-properties#property-mapping

Entity Framework Core 3.0 Many-to-Many for the same table

I am using ef core 3.0 code-first database. I have a table, Status, and I need to create a relationship to itself to list the possible "next status" List<Status> SubsequentStatuses. This is of course to systematically control the workflow of the object.
Using this at face value, it creates a one-to-many relationship and a new StatusId column in the table; however, I need to be able to set a status to be a "SubsequentStatus" to more than one Status.
For example, if there are 4 statuses:
New
In Work
Complete
Cancelled
I want to have the following
New
Subsequent Statuses
In Work
Cancelled
In Work
Subsequent Statuses
Complete
Cancelled
Complete
None
Cancelled
None
Notice that "Cancelled" is related to both "New" and "In Work"
Here are the classes and config that I have at this point:
public class EstimateStatus
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<EstimateStatusRel> SubsequentStatuses { get; set; }
}
public class EstimateStatusRel
{
public int EstimateStatusId { get; set; }
public EstimateStatus EstimateStatus { get; set; }
public int SubsequentStatusId { get; set; }
public EstimateStatus SubsequentStatus { get; set; }
}
public class SapphireContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EstimateStatusRel>().HasKey(x => new { x.EstimateStatusId, x.SubsequentStatusId });
modelBuilder.Entity<StatusRel>()
.HasOne(pt => pt.Status)
.WithMany(p => p.SubsequentStatuses)
.HasForeignKey(pt => pt.StatusId);
}
}
The issue this is creating, is that when Entity Framework is building the migration, it errors out about the multiple cascading delete action, but when I add the NoAction modifier to the modelBuilder fluent API, it still does not clear the error
It ended up being because I didn't specify an OnDelete action
This is my final config:
modelBuilder.Entity<EstimateStatusRel>()
.HasOne(pt => pt.Status)
.WithMany(p => p.SubsequentStatus)
.HasForeignKey(pt => pt.EstimateStatusId)
.OnDelete(DeleteBehavior.NoAction);
For self-reference in one-to-many relationships, you could try the below code:
public class EstimateStatus
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public EstimateStatus ParentStatuses { get; set; }
public virtual ICollection<EstimateStatus> SubsequentStatuses { get; set; }
}
public class TestDbContext:DbContext
{
public TestDbContext (DbContextOptions<TestDbContext> options):base(options)
{ }
public DbSet<EstimateStatus> EstimateStatuse { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EstimateStatus>()
.HasMany(e => e.SubsequentStatuses)
.WithOne(s => s.ParentStatuses)
.HasForeignKey(e => e.ParentId);
}
}

Entity Framework 6, Invalid Column Name - Incorrect Mapping

I solved this by adding in the ForeignKey("Route") data annotation like this:
[ForeignKey("Route")]
public Guid rnh_rtefk { get; set; }
this is my first attempt at using EF.
I have created a model using Code First from database in my MVC app using EF 6.0.0.0
In my database I have a table of Routes and a table of RunSheetHeader. A route can have many RunSheetHeader and a RunSheetHeader can have one Route. The Routes primary key is Routes.rte_pk and this maps to the foreign key: RunSheetHeader.rnh_rtefk.
The code generated is this:
public partial class Route
{
public Route()
{
RunSheetHeaders = new HashSet<RunSheetHeader>();
}
[Key]
public Guid rte_pk { get; set; }
[Required]
[StringLength(50)]
public string rte_name { get; set; }
public virtual ICollection<RunSheetHeader> RunSheetHeaders { get; set; }
}
[Table("RunSheetHeader")]
public partial class RunSheetHeader
{
public RunSheetHeader()
{
RunSheetDetails = new HashSet<RunSheetDetail>();
}
[Key]
public Guid rnh_pk { get; set; }
[Column(TypeName = "date")]
public DateTime rnh_date { get; set; }
public Guid rnh_rtefk { get; set; }
public virtual Route Route { get; set; }
public virtual ICollection<RunSheetDetail> RunSheetDetails { get; set; }
}
This is from the Context class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Route>()
.HasMany(e => e.RunSheetHeaders)
.WithRequired(e => e.Route)
.HasForeignKey(e => e.rnh_rtefk)
.WillCascadeOnDelete(false);
modelBuilder.Entity<RunSheetHeader>()
.HasMany(e => e.RunSheetDetails)
.WithRequired(e => e.RunSheetHeader)
.HasForeignKey(e => e.rnd_rnhfk)
.WillCascadeOnDelete(false);
}
The error I get is:
"Invalid column name 'Route_rte_pk'."
and the SQL shows up in SQL Profiler as:
SELECT
1 AS [C1],
[Extent1].[rnh_pk] AS [rnh_pk],
[Extent1].[rnh_date] AS [rnh_date],
[Extent1].[rnh_rtefk] AS [rnh_rtefk],
[Extent1].[Route_rte_pk] AS [Route_rte_pk]
FROM [dbo].[RunSheetHeader] AS [Extent1]
From reading the other answers here regarding similar problems it seems to be a problem with mapping the correct foreign keys, but it looks to me like that has been done correctly. Can anyone spot what I am missing?
Thanks for any help
I found 2 possible solutions to this:
1.
[ForeignKey("Route")]
public Guid rnh_rtefk { get; set; }
or 2.
[ForeignKey("rnh_rtefk")]
public virtual Route Route { get; set; }
Both get rid of the error, but I was advised that the second option is the better one to use.
the following code is running just fine, are you sure your OnModelCreating is well called ?
namespace testef {
public partial class Route {
public Route() {
RunSheetHeaders = new HashSet<RunSheetHeader>();
}
[Key]
public Guid rte_pk { get; set; }
[Required]
[StringLength(50)]
public string rte_name { get; set; }
public virtual ICollection<RunSheetHeader> RunSheetHeaders { get; set; }
}
[Table("RunSheetHeader")]
public partial class RunSheetHeader {
public RunSheetHeader() {
//RunSheetDetails = new HashSet<RunSheetDetail>();
}
[Key]
public Guid rnh_pk { get; set; }
[Column(TypeName = "date")]
public DateTime rnh_date { get; set; }
public Guid rnh_rtefk { get; set; }
public virtual Route Route { get; set; }
//public virtual ICollection<RunSheetDetail> RunSheetDetails { get; set; }
}
// ---------------
public class TestEFContext : DbContext {
public TestEFContext(String cs)
: base(cs) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Route>()
.HasMany(e => e.RunSheetHeaders)
.WithRequired(e => e.Route)
.HasForeignKey(e => e.rnh_rtefk)
.WillCascadeOnDelete(false);
//modelBuilder.Entity<RunSheetHeader>()
// .HasMany(e => e.RunSheetDetails)
// .WithRequired(e => e.RunSheetHeader)
// .HasForeignKey(e => e.rnd_rnhfk)
// .WillCascadeOnDelete(false);
}
public DbSet<Route> Routes { get; set; }
}
class Program {
String cs = #"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext ctx = new TestEFContext(cs)) {
Route r = new Route {
rte_pk = Guid.NewGuid(),
rte_name = "test"
};
r.RunSheetHeaders.Add(new RunSheetHeader {
rnh_pk = Guid.NewGuid(),
rnh_date = DateTime.Now
});
ctx.Routes.Add(r);
ctx.SaveChanges();
Console.WriteLine(ctx.Routes.Count());
}
using (TestEFContext ctx = new TestEFContext(cs)) {
foreach (Route r in ctx.Routes) {
Console.WriteLine(r.rte_name);
foreach (RunSheetHeader rsh in r.RunSheetHeaders) {
Console.WriteLine(" {0}", rsh.rnh_date);
}
}
}
}
}
}