Laden...

Wieso bekomme ich bei einem EF Core Sqlite Zugriff "No such table" Fehler, aber Tabelle existiert?

Erstellt von Steven85 vor 3 Jahren Letzter Beitrag vor 3 Jahren 1.834 Views
Steven85 Themenstarter:in
99 Beiträge seit 2011
vor 3 Jahren
Wieso bekomme ich bei einem EF Core Sqlite Zugriff "No such table" Fehler, aber Tabelle existiert?

Hallo zusammen,

ich bekomme beim Zugriff auf ein View welches definitiv auf der Sqlite DB existiert den Fehler "no such table: VW_Test". Der generelle Zugriff auf die Tabellen funktioniert wunderbar. Könnt ihr mir evtl. sagen was hier das Problem ist?


        public DbSet<VW_Test> VW_Test { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite(@"Data Source=D:\Daten\EntityFrameworkTutorial.db");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<VW_Test>()
                        .HasNoKey()
                        .ToView("VW_Test");

            base.OnModelCreating(modelBuilder);
        }


public class VW_Test
    {
        public string Vorname { get; set; }
        public string Nachname { get; set; }
    }


private static void UseCase_QueryTypes(DataContext dbContext)
        {
            var result = dbContext.Set<VW_Test>().ToList();
        }

16.806 Beiträge seit 2008
vor 3 Jahren
 .ToView(&quot;VW_Test&quot;);

Views sind keine Tabellen. Views sind Views.
Die View muss existieren.

Des weiteren kann das hier nicht korrekt sein:

var result = dbContext.Set<VW_Test>().ToList();

Du deklarierst das Set ja entsprechend:

  public DbSet<VW_Test> VW_Test { get; set; }

Dann nutze es auch, zB mit

myDbContext.VW_Test

PS: Underlines haben in Var-Names in C# eigentlich nicht zu suchen 😉

Steven85 Themenstarter:in
99 Beiträge seit 2011
vor 3 Jahren

Das hier erzeugt leider den selben Fehler.

var result = dbContext.VW_Test.ToList();

Woher kommt .ToView, das findet er leider nicht?

Danke für den Hinweis mit dem Unterstrich, ist eh erstmal alles nur ein Test.
Das View existiert zu 100% und beinhaltet auch Daten.

16.806 Beiträge seit 2008
vor 3 Jahren

Woher kommt .ToView, das findet er leider auch nicht?

ToView ist Teil des ModelBuilders.

Das View existiert zu 100% und beinhaltet auch Daten.

Offenbar nicht für den Context; sonst würde der Fehler nicht kommen.
Verwendest den falschen Context? Einen unshared Context?

Aber mehr als

modelBuilder.Entity<VW_Test>().HasNoKey().ToView("VW_Test");

ist nicht notwendig, wenn die View existiert.

Steven85 Themenstarter:in
99 Beiträge seit 2011
vor 3 Jahren

Das hier ist mein gesamter Context:


public class DataContext : DbContext
    {
        // Für die zu erzeugende Tabelle nach dem Code first Prinzip
        public DbSet<Person> Personen { get; set; }
        public DbSet<Geschlecht> Geschlechter { get; set; }
        public DbSet<Herkunft> Herkunft { get; set; }
        public DbSet<Kontinent> Kontinent { get; set; }
        public DbSet<Hobby> Hobby { get; set; }
        public DbSet<PersonHobby> PersonHobby { get; set; }
        public DbSet<VW_Test> VW_Test { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite(@"Data Source=D:\Daten\EntityFrameworkTutorial.db");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            var personBuilder = Build<Person>(modelBuilder);
            var geschlechtBuilder = Build<Geschlecht>(modelBuilder);
            var herkunftBuilder = Build<Herkunft>(modelBuilder);
            var kontinentBuilder = Build<Kontinent>(modelBuilder);
            var hobbyBuilder = Build<Hobby>(modelBuilder);
            var personhobbyBuilder = Build<PersonHobby>(modelBuilder);

            // Property Bedingungen festlegen
            personBuilder
                .Property(x => x.Geburtsdatum)
                .IsRequired();
            personBuilder
                .Property(x => x.HerkunftId)
                .IsRequired();
            personBuilder
                .Property(x => x.IQ)
                .HasDefaultValue(0)
                .IsRequired();
            herkunftBuilder
                .Property(x => x.Deutschsprachig)
                .HasDefaultValue(false);

            // 1 zu n Beziehungen
            personBuilder
                .HasOne(x => x.Geschlecht)
                .WithMany(x => x.Personen)
                .HasForeignKey(x => x.GeschlechtId);
            personBuilder
                .HasOne(x => x.Herkunft)
                .WithMany(x => x.Personen)
                .HasForeignKey(x => x.HerkunftId);
            herkunftBuilder
                .HasOne(x => x.Kontinent)
                .WithMany(x => x.Herkunft)
                .HasForeignKey(x => x.KontinentId);

            // m zu n Beziehungen
            personhobbyBuilder
                .HasOne(x => x.Person)
                .WithMany(x => x.PersonenHobbys)
                .HasForeignKey(x => x.PersonId);
            personhobbyBuilder
                .HasOne(x => x.Hobby)
                .WithMany(x => x.PersonenHobbys)
                .HasForeignKey(x => x.HobbyId);

            // View
            modelBuilder.Entity<VW_Test>()
                        .HasNoKey()
                        .ToView("VW_Test");

            base.OnModelCreating(modelBuilder);
        }

        private EntityTypeBuilder<T> Build<T>(ModelBuilder mb)
            where T : Entity
        {
            var entity = mb.Entity<T>();
            entity.HasKey(x => x.Id);

            // Shadow Properties anlegen die für Entity nicht sichtbar sind und autom. gefüllt werden
            entity.Property<string>("LatestUser")
                  .HasDefaultValue("Admin");

            return entity;
        }
    }

Der Zugriff auf alle anderen Tabellen klappt problemlos.
Anbei noch ein Auszug aus meinem DB Browser, die Ansicht existiert und kann auch mit SQL abgerufen werden im DB Browser.

16.806 Beiträge seit 2008
vor 3 Jahren

Der Zugriff auf alle anderen Tabellen klappt problemlos.

Wie gesagt; Views sind keine(!) Tabellen.
Das sind sind Äpfel, das andere sind Birnen.

Funktionierts, wenn Du mit Raw-SQL die View-Daten abrufst?
Ansonsten mal das Logging aktivieren; seh ich bei Dir auch nirgends.

Übersicht über Protokollierung und Abfangfunktionen

Wie schon im anderen Thread gesagt: les Dir mal die Doku einmal komplett durch.
Ja, kostet mal ein Tag. Und Du wirst nicht alles 100% im Kopf behalten, aber Du hast dann wenigstens grundlegende Dinge wie Error Handling und Logging gesehen und weißt, wo Du Infos her bekommst, die Du brauchst.

Vielleicht werden Views bei Sqlite auch nicht unterstützt; vllt steht dazu auch was in der Doku. Sqlite hat ja ohnehin unmengen an Einschränkungen im Vergleich zu einem echten SQL Server.
Ich verwende sie problemlos mit allen Varianten des SQL Servers.

Steven85 Themenstarter:in
99 Beiträge seit 2011
vor 3 Jahren

Mit Raw Sql kommt der selbe Fehler "no such table".

 
dbContext.VW_Test.FromSqlRaw(@"select * from VW_Test").ToList()

Das Thema Logging wurde in meinem Tutorial erst jetzt behandelt. Hier spuckt die Console nun folgendes aus:

Fehlermeldung:
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 5.0.1 initialized 'DataContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT "v"."Nachname", "v"."Vorname"
FROM "VW_Test" AS "v"
fail: Microsoft.EntityFrameworkCore.Query[10100]
An exception occurred while iterating over the results of a query for context type 'Beispielanwendung_Einfach.DataContext'.
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: VW_Test'.
at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
at Microsoft.Data.Sqlite.SqliteCommand.PrepareAndEnumerateStatements(Stopwatch timer)+MoveNext()
at Microsoft.Data.Sqlite.SqliteCommand.GetStatements(Stopwatch timer)+MoveNext()
at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.Enumerator.InitializeReader(DbContext _, Boolean result) at Microsoft.EntityFrameworkCore.Storage.NonRetryingExecutionStrategy.Execute[TState,TResult](TState state, Func3 operation, Func3 verifySucceeded) at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.Enumerator.MoveNext()
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: VW_Test'.
at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
at Microsoft.Data.Sqlite.SqliteCommand.PrepareAndEnumerateStatements(Stopwatch timer)+MoveNext()
at Microsoft.Data.Sqlite.SqliteCommand.GetStatements(Stopwatch timer)+MoveNext()
at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.Enumerator.InitializeReader(DbContext _, Boolean result) at Microsoft.EntityFrameworkCore.Storage.NonRetryingExecutionStrategy.Execute[TState,TResult](TState state, Func3 operation, Func3 verifySucceeded) at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable1.Enumerator.MoveNext()

16.806 Beiträge seit 2008
vor 3 Jahren

Jo, dann kommt der Fehler auch von Sqlite und nicht von EFCore.
Damit kannste Dein ModelBinding offenbar als Ursache ausschließen: dank Logging.

Daher erneut der Hinweis:

Verwendest den falschen Context?

Das Thema Logging wurde in meinem Tutorial erst jetzt behandelt.

Daher der Hinweis - in Deinem eigenen Interesse - mal die Doku zu überfliegen 😉

Steven85 Themenstarter:in
99 Beiträge seit 2011
vor 3 Jahren

Was genau meinst du mit falschen Context?

16.806 Beiträge seit 2008
vor 3 Jahren

Muss ja ein Grund haben, dass über den SQL Command keine View gefunden wird; Du sie aber in der Sql Editor Anwendung siehst.
Evtl. arbeitest gegen die falschen DB oder den falschen DbContext. Ist ja dann naheliegend, dass es zwei verschiedene sein könnten.

Im Snippet arbeitest Du gegen eine ganz andere DB-Datei als im Screenshot.

  optionsBuilder.UseSqlite(@"Data Source=D:\Daten\EntityFrameworkTutorial.db");

Ich kann ja aus der Ferne auch nur Raten und Dir Tipps geben wo zu suchen.

Steven85 Themenstarter:in
99 Beiträge seit 2011
vor 3 Jahren

Ne, es gibt nur eine DB. Ich habe den ConnectionString zur besseren Lesbarkeit immer gekürzt, der geht definitiv auf die richtige DB. Und es gibt nur einen Context. Ich gehe davon aus das Sqlite evtl. das nicht unterstützt. Habe bei Google auch nichts gefunden.

16.806 Beiträge seit 2008
vor 3 Jahren

Ich gehe davon aus das Sqlite evtl. das nicht unterstützt.

Das macht wenig Sinn, wenn Du um 15:27 Uhr geschrieben hast, dass die View über den Editor einwandfrei funktioniert.
Warum sollte es dann plötzlich Sqlite nich mehr unterstützen?

EF Core (falls dies es nicht unterstützt) hast Du als Fehlerquelle bereits ausschließen können, weil Du ja den Raw-Command getestet hast, der ebenfalls not found wirft.
Die Fehlerquelle muss also irgendwo an der Sqlite Datei liegen, mit der Du arbeitest - was auch immer.

16.806 Beiträge seit 2008
vor 3 Jahren

Ich hab mal Deine Situation nachgestellt und mein Verdacht, dass der Fehler bei Dir liegt, erhärtet sich.

Das DB Editor Tool ist selten dämlich, dass man jegliche Änderung aktiv mit irgendeinem Speicher-Button bestätigen muss.
Macht man das nicht, sieht es in der UI so aus als ob alles da sei: aber bei Abfragen wirds dann nicht gefunden.

Du hast also offenbar die View in der UI erstellt, ohne, dass diese in der Datenbank-Datei selbst erstellt wurde.

Man wird aber bei jeglichen Aktionen vom Tool darauf hingewiesen/gefragt, ob die Änderungen in der Datei gespeichert werden sollen.

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var dbContext = new MyDbContext(@"Data Source=C:\Users\Ben\Desktop\Test.db");
            
            Console.WriteLine();
            Console.WriteLine("Table:");
            foreach (var person in dbContext.Persons.ToList())
            {
                Console.WriteLine($"{person.Vorname} {person.Nachname}");
            }
            
            Console.WriteLine();
            Console.WriteLine("View Raw:");
            foreach (var person in dbContext.PersonViews.FromSqlRaw("SELECT Vorname, Nachname FROM View_Persons"))
            {
                Console.WriteLine($"{person.Vorname} {person.Nachname}");
            }
            
            Console.WriteLine();
            Console.WriteLine("View:");
            foreach (var person in dbContext.PersonViews.ToList())
            {
                Console.WriteLine($"{person.Vorname} {person.Nachname}");
            }

            Console.ReadKey();
        }
    }

    public class MyDbContext : DbContext
    {
        private readonly string _connectionString;

        public MyDbContext(string connectionString)
        {
            _connectionString = connectionString;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite(_connectionString);
            //optionsBuilder.LogTo(Console.WriteLine);
        }
        public DbSet<PersonEntiy> Persons { get; set; }
        public DbSet<PersonView> PersonViews { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<PersonEntiy>().ToTable("Persons").HasKey(e => e.Id);
            modelBuilder.Entity<PersonView>().ToView("View_Persons").HasNoKey();
        }
    }

    public class PersonEntiy
    {
        public int Id { get; set; }
        public string Vorname { get; set; }
        public string Nachname { get; set; }
    }

    public class PersonView
    {
        public string Vorname { get; set; }
        public string Nachname { get; set; }
    }
}

Output:

Table:
Peter Pan
James Bond
Harry Potter

View Raw:
Peter Pan
James Bond
Harry Potter

View:
Peter Pan
James Bond
Harry Potter

Man hätte also einfach nur auf den Fehler von Sqlite hören sollen: not found.
Und wenns nicht da ist, dann ists eben auch nicht in der Datei.

Steven85 Themenstarter:in
99 Beiträge seit 2011
vor 3 Jahren

Ich habe den Fehler gefunden. Das View ist jedes mal verschwunden wenn man im DB Browser die Verbindung schließt und wieder öffnet. Hier muss man noch den Button "Änderungen schreiben" nutzen, erst dann existiert das View tatsächlich. Vorher kann man aber schon via SQL in dem Tool damit Abfragen generieren. Sorry, ich arbeite erst jetzt mit diesem Tool und hab es nicht bemerkt. Danke für deine Hilfe.

16.806 Beiträge seit 2008
vor 3 Jahren

Kann immer passieren; bin auch drauf reingefallen gestern bei der ersten Nutzung 😉