none
Hilfe bei Problemen mit Imports von EF-Power-Tools RRS feed

  • Frage

  • Hallo,

    1. Frage:

    ich nutze in meiner Anwendung die EF-Core-Power-Tools. Damit lasse ich mir die Tabellen aus der Datenbank als Entities und auch die DbContext erstellen.

    Nun habe ich aber eigene Änderungen an der DbContext vorzunehmen.  Z.b. um auf eine gespeicherte Prozedur zugreifen zu können muss ich die DbContext erweitern.

    Wenn ich nun aber wieder eine weitere Tabelle über die EF-Power-Tools importiere, wird ja jedes mal die erstellte DbContext neu erstellt und meine Änderungen gehen verloren.

    Nun habe ich mir überlegt, eine eigene DbContext zu erstellen welche von der automatisch generierten ableitet. Wie muss ich den Constructor aufbauen, damit ich die DbContext in die Startup einbinden kann? 

    2. Frage:

    Ich habe eine Tabelle, welche die EF-Tools importiert. Diese Tabelle enthält ein bool? Feld. Dieses bereitet aber Probleme bei Bindung an eine InputCheckbox. Hier wird bool vorausgesetzt. Nun kann ich in der Klasse einfach das Fragezeichen entfernen... jedoch werden wieder bei Aktualisierung durch die EF-Power-Tools die Klassen neu erstellt und eigene Änderungen gehen verloren. Wie umgehe ich das Problem OHNE die SQL Tabelle ändern zu müssen? Wenn ich von der Klasse ableite, müsste ich ja die neue abgeleitete Klasse der DbContext zufügen... und hier wären wir dann wieder bei Frage 1. :)  Also 

    3. Frage:

    Wie füge ich einer ggf. in Frage 1 abgeleiteten neuen DbContext DbSets hinzu?


    .::datekk::.


    • Bearbeitet datekk2 Mittwoch, 6. Januar 2021 13:02
    Mittwoch, 6. Januar 2021 12:56

Antworten

  • Hi,

    der Namespace passt nicht, daher ist deine Klasse eine andere als die der EFCore PowerTools.

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Ignore<SpKundensucheModel>();
        modelBuilder.Query<SpKundensucheModel>();
        OnModelCreatingPartial(modelBuilder);
    }

    entfernst Du aus deiner Klasse und schreibst dafür dann:

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
    {
        modelBuilder.Ignore<SpKundensucheModel>();
        modelBuilder.Query<SpKundensucheModel>();
    }

    Die von den EFCore PowerTools erzeugte DbContext Klasse sollte ihrerseits den Aufruf auf OnModelCreatingPartial bereits in OnModelCreating durchführen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Mittwoch, 13. Januar 2021 11:28
    Moderator

Alle Antworten

  • Hi,

    zu Frage 1 und 3: Nimm keine Ableitung, sondern eine partielle Klasse (partial class).

    Also einfach in deinem Projekt, das die von den EFCore PowerTools erzeugte DbContext Klasse enthält, eine weitere Klasse einfügen und dort deine Erweiterungen einbauen.

    using System.Diagnostics;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Infrastructure;
    
    namespace <DeinNamespace>
    {
        public partial class <DeinContext> : DbContext
        {
            public virtual DbSet<EigeneKlasse> EigenesDbSet { get; set; }
    
            partial void OnModelCreatingPartial( ModelBuilder modelBuilder )
            {
                ...
            }
            ...
        }
    }

    Zu Frage 2 hatte ich auch schon bei Erik gefragt und auch eine (optionale, da durch den Einstellungen Dialog aktivierbare) Lösung geschrieben. Der Pull Request wurde aber abgelehnt, hat ihm leider nicht so gefallen. Er hat aber, soweit ich das verstanden habe, vor ca. 3 Wochen eine eigene Lösung integriert. Schau daher mal, ob die neueste Version bei dir Abhilfe schafft.

    Ansonsten bleibt dir nur, das BIT Feld mit NOT NULL zu versehen und keinen Defaultwert vergeben (auch nicht 0), da genau dann das Problem entsteht.



    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Mittwoch, 6. Januar 2021 14:44
    Moderator
  • Hallo und vielen Dank Stefan,

    leider kann ich die Partial Class aber so nicht einrichten. Irgendwas fehlt. Wie übergebe ich denn den Connection String? Dein Codebeispiel hat keinen Constructor, welcher Optionen entgegen nimmt.

    Baue ich die Konstruktoren wie in der "Standard" ApplicationDbContext erhalte ich folgende Fehlermeldung wenn ich die "neue" OwnDbContext in die Startup eintrage:

    ggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: WebApp.data.sqltables.WebAppDbContext Lifetime: Scoped ImplementationType: WebApp.data.sqltables.WebAppDbContext': Unable to activate type 'WebApp.data.sqltables.WebAppDbContext'. The following constructors are ambiguous:
    Void .ctor(Microsoft.EntityFrameworkCore.DbContextOptions`1[WebApp.Data.OwnDbContext])


    .::datekk::.



    • Bearbeitet datekk2 Donnerstag, 7. Januar 2021 13:49
    Donnerstag, 7. Januar 2021 13:44
  • Hi,

    warum sollte das mit der Partial Class so nicht gehen? Du brauchst in deiner Klasse keinen Konstruktur, auch keinen ConnectionString, das passiert alles automatisch in der von den EFCore PowerTools erzeugten (partiellen) DbContext Klasse. Deine (ebenfalls partielle) Klasse ist eben eine Erweiterung.

    Du musst also rein gar nichts tun außer eben die partielle Klasse mit deinen Erweiterungen zu versehen (so wie im Beispiel gezeigt)


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Donnerstag, 7. Januar 2021 14:20
    Moderator
  • 2. Frage:

    Ich habe eine Tabelle, welche die EF-Tools importiert. Diese Tabelle enthält ein bool? Feld. Dieses bereitet aber Probleme bei Bindung an eine InputCheckbox. Hier wird bool vorausgesetzt. Nun kann ich in der Klasse einfach das Fragezeichen entfernen... jedoch werden wieder bei Aktualisierung durch die EF-Power-Tools die Klassen neu erstellt und eigene Änderungen gehen verloren.

    In der neuesten EFCore PowerTools Version ist das Problem derart behoben, dass es im Advanced... Dialog eine neue Einstellung für Bit Felder mit Defaultwerten gibt, die dann im erzeugten Code den Defaultwert entfernen und damit eine bool und keine bool? Property erzeugen. Eben mal probiert.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Montag, 11. Januar 2021 14:56
    Moderator
  • Das hört sich ja gut an. Wie kann ich die EFCore Power Tools updaten?

    .::datekk::.

    Mittwoch, 13. Januar 2021 07:38
  • Hi,

    VS 2019
     -> Menü "Erweiterungen"
       -> Erweiterungen verwalten
         -> Updates


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 13. Januar 2021 08:05
    Moderator
  • Ich bekomme das nicht hin... hier mal meine Klasse:

    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using WebApp.Data.Prozeduren;
    
    
    namespace WebApp.Data
    {
        public partial class OwnDbContext : DbContext
        {
            
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Ignore<SpKundensucheModel>();
                modelBuilder.Query<SpKundensucheModel>();
                OnModelCreatingPartial(modelBuilder);
            }
    
    
            public List<SpKundensucheModel> Kundensuche(string sqlQuery)
            {
                List<SpKundensucheModel> lst = new List<SpKundensucheModel>();
                try
                {
                    lst = this.Query<SpKundensucheModel>().FromSqlRaw<SpKundensucheModel>(sqlQuery).ToList();
                }
                catch (Exception ex)
                {
    
                    return null;
                }
    
                return lst;
    
    
            }
    
            partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
        }
    }

    In der Razor-Seite habe ich dann folgenden Code:

     OwnDbContext owndb = new OwnDbContext();
    
    void Suche()
        {
            string sqlQuery;
            suchtext = textsuchfeld;
            string a = ((char)34).ToString();
            string b = ((char)32).ToString();
            if (suchtext == "")
            {
                suchtext = "%";
            }
            suchtext = a + suchtext;
            suchtext = suchtext.Replace(b, "*" + a + " AND " + a);
    
            suchtext = suchtext + "*" + a;
    
            if (wahlVertrieb > 0 )
            {
                sqlQuery = String.Format("EXEC spKundensuche '{0}',{1},{2}", suchtext, typWahl, wahlVertrieb);
            } else
            {
                sqlQuery = String.Format("EXEC spKundensuche '{0}',{1},{2}", suchtext, typWahl, "0");
            }
    
    
            
            var result = owndb.Kundensuche(sqlQuery);
            Suchergebnis = result;
        }

    Nutze ich die  'var result = WebAppDbContext(sqlQuery)' (=die von den Tools erzeugte DbContext in der die Kundensuche ebenfalls händisch eingepflegt wurde), so erhalte ich Suchergebnisse.... Nutze ich die OwnDbContext erhalte ich keine Suchergebnisse. Irgendwas scheine ich da falsch zu machen.


    .::datekk::.


    • Bearbeitet datekk2 Mittwoch, 13. Januar 2021 09:04
    Mittwoch, 13. Januar 2021 09:04
  • Hi,

    ich hab dir doch mehrfach gesagt, dass Du mit einer partial class der von den EFCore PowerTools erzeugten DbContext Klasse und nicht mit einer eigenen DbContext Klasse (der ja nunmal alles fehlt, was man braucht) arbeiten sollst.

    Wenn der erzeugte DbContext also WebAppDbContext heißt, muss deine partielle Klasse ebenfalls so heißen.

    Daher die Frage: Warum machst Du das nicht? Mag ja sein, dass es einen Grund dafür gibt aber welcher das sein sollte, mag sich mir grad nicht erschließen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Mittwoch, 13. Januar 2021 09:41
    Moderator
  • Sorry, dann hatte ich das tatsächlich nicht so richtig verstanden, und tue ich scheinbar immer noch nicht. Bitte sei gnädig, ich bin Autodidakt... 

    Also, jetzt habe ich die neue Klasse mit den Erweiterungen genau so genannt wie die erstellte DbContext....

    Der Dateiname der Klasse ist dennoch OwnDbContext.cs, die Klasse baut sich aber so auf:

    namespace WebApp.Data
    {
        public partial class WebDbContext : DbContext
        {
            
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Ignore<SpKundensucheModel>();
                modelBuilder.Query<SpKundensucheModel>();
                OnModelCreatingPartial(modelBuilder);
            }
    
    
            public List<SpKundensucheModel> Kundensuche(string sqlQuery)
            {
                List<SpKundensucheModel> lst = new List<SpKundensucheModel>();
                try
                {
                    lst = this.Query<SpKundensucheModel>().FromSqlRaw<SpKundensucheModel>(sqlQuery).ToList();
                }
                catch (Exception ex)
                {
    
                    return null;
                }
    
                return lst;
    
    
            }
    
            partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
        }
    }

    Nun bekomme ich aber die Fehlermeldung: 


    Fehler CS0104 '"WebDbContext" ist ein mehrdeutiger Verweis zwischen "WebApp.Data.WebDbContext" und "WebApp.data.sqltables.WebDbContext".

    Schau bitte nochmal drüber :)


    .::datekk::.

    Mittwoch, 13. Januar 2021 11:18
  • Hi,

    der Namespace passt nicht, daher ist deine Klasse eine andere als die der EFCore PowerTools.

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Ignore<SpKundensucheModel>();
        modelBuilder.Query<SpKundensucheModel>();
        OnModelCreatingPartial(modelBuilder);
    }

    entfernst Du aus deiner Klasse und schreibst dafür dann:

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
    {
        modelBuilder.Ignore<SpKundensucheModel>();
        modelBuilder.Query<SpKundensucheModel>();
    }

    Die von den EFCore PowerTools erzeugte DbContext Klasse sollte ihrerseits den Aufruf auf OnModelCreatingPartial bereits in OnModelCreating durchführen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Mittwoch, 13. Januar 2021 11:28
    Moderator
  • Jeeetzt.... lieben Dank. Es läuft :)

    1000 Dank.


    .::datekk::.

    Mittwoch, 13. Januar 2021 12:14
  • Also ich habe die EF Power Tool geupdatet und die Tabellen neu eingelesen und auch eine neue DbContext erstellen lassen. In der DbContext habe ich jetzt z.B. bei einem bool-Feld stehen: entity.Property(e => e.IsDeletedLocally).HasDefaultValueSql("((0))");

    Allerdings werden die Tabellenfelder immer noch auf bool? gesetzt:

    public bool? IsDeletedLocally { get; set; }

    Womit dann im Code beim binden an eine InputCheckbox immer noch der Fehler auftaucht, dass der Typ "bool?" nicht implizit in "bool" konvertiert werden kann.



    .::datekk::.

    Mittwoch, 13. Januar 2021 13:13
  • Hi,

    Diese Option muss aktiviert sein.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 13. Januar 2021 14:16
    Moderator
  • Ja, das ist sie bei mir auch. Die Tabelle wird aber trotzdem mit bool? als Klasse zugefügt.

    .::datekk::.

    Mittwoch, 13. Januar 2021 14:18
  • Visual Studio auch neu gestartet? Falls ja, poste bitte mal das CREATE TABLE Statement für deine Tabelle mit den BIT Feldern.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 13. Januar 2021 14:22
    Moderator
  • Create Table aus dem SQL Management Studio?

    .::datekk::.

    Mittwoch, 13. Januar 2021 14:28
  • Create Table aus dem SQL Management Studio?

    Ja, Hauptsache ist aber, es steht alles drin wie die DEFAULT CONSTRAINTS ... Also bspw. so:

    CREATE TABLE [dbo].[TestBitColumns](
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Hidden] [bit] NOT NULL,
    	[Visible] [bit] NOT NULL,
     CONSTRAINT [PK_TestBitColumn] PRIMARY KEY CLUSTERED 
    (
    	[ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    
    ALTER TABLE [dbo].[TestBitColumns] ADD  CONSTRAINT [DF_TestBitColumns_Hidden]  DEFAULT ((1)) FOR [Hidden]
    GO
    
    ALTER TABLE [dbo].[TestBitColumns] ADD  CONSTRAINT [DF_TestBitColumns_Visible]  DEFAULT ((0)) FOR [Visible]
    GO


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 13. Januar 2021 14:30
    Moderator
  • Ich habs mal ein bisschen gekürzt weil die Tabelle recht viele Spalten hat.

    CREATE TABLE [dbo].[Kundenliste](
    	[ID_Kunde] [int] IDENTITY(1,1) NOT NULL,
    	
    	....
    	[IsDeletedLocally] [bit] NULL,
    
    	[VertriebsID] [int] NULL,
    	
    	[Neukunde] [bit] NULL,
    
    	[IsPrimeryContact] [bit] NULL,
    	
    	[Ueberregional] [bit] NULL,
    	[
    
    	[UId] [uniqueidentifier] NOT NULL,
     CONSTRAINT [Kundenliste$PrimaryKey] PRIMARY KEY CLUSTERED 
    (
    	[ID_Kunde] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO
    
    ALTER TABLE [dbo].[Kundenliste] ADD  CONSTRAINT [DF__Kundenlis__IsDel__5AEE82B9]  DEFAULT ((0)) FOR [IsDeletedLocally]
    GO
    
    
    ALTER TABLE [dbo].[Kundenliste] ADD  CONSTRAINT [DF__Kundenlis__IsPri__5CD6CB2B]  DEFAULT ((0)) FOR [IsPrimeryContact]
    GO
    
    ALTER TABLE [dbo].[Kundenliste] ADD  CONSTRAINT [DF_Kundenliste_UId]  DEFAULT (newid()) FOR [UId]
    GO
    
    
    
    EXEC sys.sp_addextendedproperty @name=N'MS_SSMA_SOURCE', @value=N'NeuesBackend.[Kundenliste].[IsDeletedLocally]' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Kundenliste', @level2type=N'COLUMN',@level2name=N'IsDeletedLocally'
    GO
    
    
    EXEC sys.sp_addextendedproperty @name=N'MS_SSMA_SOURCE', @value=N'NeuesBackend.[Kundenliste].[IsPrimeryContact]' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Kundenliste', @level2type=N'COLUMN',@level2name=N'IsPrimeryContact'
    GO
    


    .::datekk::.

    Mittwoch, 13. Januar 2021 14:38
  • In deinem Fall liegt das daran, dass die Spalten NULL erlauben. Das wiederum scheint auch die neueste Version der EFCore PowerTools bei der Prüfung auf die SQL Default Werte nicht umzusetzen.

    Letztendlich ist das aber auch richtig so, da die Spalte ja nunmal NULL erlaubt. Also ist die Umsetzung als bool? korrekt.

    BIT Felder sind bei mir nur dann mit einem Standardwert versehen, wenn Sie eben kein NULL erlauben. Für die Fälle klappt das dann auch mit den EFCore PowerTools.

    Ändere daher die Spaltendefinition auf NOT NULL, dann klappt das auch. (Und sollte das nicht gehen, musst Du wohl oder übel damit leben)


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport


    Mittwoch, 13. Januar 2021 15:06
    Moderator
  • Ja, dann werde ich die Felder der SQL Tabelle umstellen. Sollte kein Problem sein. Lieben Dank für die Hilfestellung :)

    .::datekk::.


    • Bearbeitet datekk2 Donnerstag, 14. Januar 2021 11:21
    Donnerstag, 14. Januar 2021 11:06