Ich habe eine gespeicherte Prozedur, die dynamische Auswahl enthält. Etwas wie das:
ALTER PROCEDURE [dbo].[usp_GetTestRecords]
[email protected] int = 0,
[email protected] int = 0
@groupId nvarchar(10) = 0
AS
BEGIN
SET NOCOUNT ON;
DECLARE @query NVARCHAR(max)
SET @query = 'SELECT * FROM CUSTOMERS WHERE Id = ' + @groupId
/* This actually contains a dynamic pivot select statement */
EXECUTE(@query);
END
Im SSMS läuft die gespeicherte Prozedur einwandfrei und zeigt die Ergebnismenge.
In C # wird mit Entity Framework eine int
anstelle von IEnumerable
zurückgegeben.
private void LoadTestRecords()
{
TestRecordsDBEntities dataContext = new TestRecordsDBEntities();
string id = ddlGroupId.SelectedValue;
List<TestRecord> list = dataContext.usp_GetTestRecords(id); //This part doesn't work returns int
GridView1.DataSource = list;
}
Generierte Funktion für usp_GetTestRecords
public virtual int usp_GetTestRecords(string groupId)
{
var groupIdParameter = groupId != null ?
new ObjectParameter("groupId", groupId) :
new ObjectParameter("groupId", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("usp_GetTestRecords", groupIdParameter);
}
Entity Framework kann nicht erkennen, was Ihre gespeicherte Prozedur zurückgibt. Ich habe erfolgreich eine Tabellenvariable erstellt, die die Daten Ihrer SELECT-Anweisung widerspiegelt. Fügen Sie einfach in die Tabellenvariable ein und wählen Sie dann aus dieser Tabellenvariablen aus. EF sollte es abholen.
Ich bekomme dies, wenn ich eine gespeicherte Prozedur habe, die einen "exec" -Aufruf in eine temporäre Tabelle enthält, wie zum Beispiel:
insert into #codes (Code, ActionCodes, Description)
exec TreatmentCodes_sps 0
Es scheint, dass Entity Framework verwirrt wird, was von der Prozedur zurückgegeben werden soll. Die Lösung, auf die ich gestoßen bin, ist, dies oben im Sproc hinzuzufügen:
SET FMTONLY OFF
Danach ist alles gut.
Ich habe das gleiche Problem und fand eine Lösung hier
Es sollte das sein, was Sie jetzt brauchen.
Siehe die Antwort von Ladislav Mrnka in diesem Beitrag zum Stack Overflow https://stackoverflow.com/a/7131344/4318324
Ich hatte das gleiche Grundproblem.
Hinzufügen
SET FMTONLY OFF
Eine Prozedur, die Sie während des Imports importieren möchten, behebt dieses Problem. Es empfiehlt sich, die Zeile anschließend zu entfernen, es sei denn, der Zweck der Datenbank besteht ausschließlich darin, ein Schema für EF (Entity Framework) bereitzustellen.
Der Hauptgrund für die Vorsicht ist, dass EF diese Einstellung verwendet, um Datenmutationen beim Abrufen von Metadaten zu verhindern.
Wenn Sie Ihr Entitätsmodell aus einer Datenbank aktualisieren, können Prozeduren mit dieser Zeile möglicherweise die Daten in dieser Datenbank aktualisieren, indem Sie einfach versuchen, das Schema abzurufen.
Ich wollte dazu noch eine weitere Anmerkung hinzufügen, damit der andere Link nicht vollständig durchsucht werden kann.
wenn Sie versuchen möchten, FMTONLY zu verwenden, sind hier ein paar Dinge zu beachten.
wenn FMTONLY eingeschaltet ist: 1) Nur das Schema wird zurückgegeben (keine) Zeilen . Ähnlich wie das Hinzufügen einer falschen false-Anweisung zu Ihrer where-Klausel (dh "where 1 = 0") 2) Flusssteuerungsanweisungen werden ignoriert
Beispiel
fmtonly auf setzen, wenn 1 = 1 begin Wählen Sie 1 a end sonst begin Wählen Sie 1 a, 2 b Ende , während 1 = 1 Wählen Sie 1 c
Das obige gibt KEINE Zeilen und die Metadaten für jede der drei Abfragen zurück
Aus diesem Grund schlagen einige Leute vor, die Funktion so einzustellen, dass die Flusskontrolle nicht beachtet wird
wenn 1 = 0 begin fmtonly ausschalten ende
Tatsächlich könnten Sie dies verwenden, um eine Logik einzuführen, die dies verfolgt
setze fmtonly aus declare @g varchar (30) set @g = 'fmtonly wurde auf off gesetzt' wenn 1 = 0 begin Fmtonly ausschalten set @g = 'fmtonly wurde auf on gesetzt end select @g
Denken Sie SEHR SORGFÄLTIG, bevor Sie versuchen, diese Funktion zu verwenden, da dies veraltet ist und SQL möglicherweise extrem schwer zu folgen ist
die wichtigsten Konzepte, die verstanden werden müssen, sind folgende
1. EF schaltet FMTONLY ein, um zu verhindern, dass MUTATING-Daten gespeicherte Prozeduren ausführen wenn es sie während eines Modell-Updates ausführt . (woraus folgt) 2. Wenn Sie FMTONLY in einer beliebigen Prozedur ausschalten, die EF versucht, einen Schema-Scan durchzuführen, ___. (möglicherweise ANY und EACHONE) führt das Potenzial zur Veränderung der Datenbank ein Daten, wann immer * jemand * versucht, ihr Datenbankmodell zu aktualisieren .
Entity Framework gibt automatisch einen Skalarwert zurück, wenn Ihre gespeicherte Prozedur keinen Primärschlüssel in Ihrer Ergebnismenge enthält. Daher müssen Sie eine Primärschlüsselspalte in Ihre select-Anweisung einschließen oder eine temporäre Tabelle mit einem Primärschlüssel erstellen, damit Entity Framework eine Ergebnismenge für Ihre gespeicherte Prozedur zurückgeben kann.
Ich hatte das gleiche Problem, ich änderte den Namen der Rückgabefelder nach dem Schlüsselwort 'AS' und behandelte mein Problem. Ein Grund für dieses Problem ist das Benennen von Spaltennamen mit für SQL Server reservierten Schlüsselwörtern.
Das Beispiel ist Brachen:
ALTER PROCEDURE [dbo].[usp_GetProducts]
AS
BEGIN
SET NOCOUNT ON;
SELECT
, p.Id
, p.Title
, p.Description AS 'Description'
FROM dbo.Products AS p
END
Wenn Sie Ihre Modellklasse für Ihre gespeicherte Prozedur generiert haben, haben Sie versehentlich das Ergebnis der skalaren Rückgabe ausgewählt. Sie sollten Ihre gespeicherte Prozedur aus Ihrem Entitätsmodell entfernen und dann die gespeicherte Prozedur erneut hinzufügen. Im Dialog für die gespeicherte Prozedur können Sie den erwarteten Rückgabetyp auswählen.NichtBearbeiten Sie einfach den generierten Code. Dies kann jetzt funktionieren. Der generierte Code kann jedoch ersetzt werden, wenn Sie andere Änderungen an Ihrem Modell vornehmen.
Ich habe ein wenig darüber nachgedacht und denke, ich habe eine bessere/einfachere Antwort
Wenn Sie einen Komplex gespeichert haben, der das Entity-Framework schwierig gestaltet (für aktuelle Versionen von Entity Framework, die das FMTONLY-Tag verwenden, um ein Schema zu erwerben)
Überlegen Sie, ob Sie zu Beginn Ihrer gespeicherten Prozedur Folgendes tun möchten.
-- Wobei [columnlist] mit dem Schema übereinstimmt, das EF für Ihre gespeicherte Prozedur abrufen soll wenn 1 = 0 begin wählen [Spaltenliste] from [table list and joins] wobei 1 = 0 Ende
wenn Sie die Ergebnismenge in eine Tabellenvariable laden möchten, können Sie Folgendes tun, um Ihr Schema synchron zu halten
deklariert @tablevar als Tabelle ( blah int , moreblah varchar (20) ) __. wenn 1 = 0 begin Wählen Sie * aus @Tablevar Ende ... -- Laden Sie Daten in @Tablevar Wählen Sie * aus @Tablevar
Nun, ich hatte auch dieses Problem, aber nach stundenlanger Online-Suche hat keine der oben genannten Methoden geholfen. Endlich erfuhr ich, dass es passieren wird, wenn Ihre Store-Prozedur einige Parameter als Null erhält und Fehler in der Abfrageausführung auftreten. Entity Framework generiert eine Methode für die Speicherprozedur, indem das komplexe Entitätsmodell definiert wird. Aufgrund dieses Nullwerts gibt Ihre Store-Prozedur einen Int-Wert zurück.
Überprüfen Sie Ihre Store-Prozedur, indem Sie entweder leere Ergebnismenge mit Nullwerten angeben. Es wird Ihr Problem beheben. Hoffnungsvoll.
Wenn Sie dies tun müssen, ist es möglicherweise besser, nur einen Teil des dbcontext zu erstellen und selbst die C # -Funktion zu erstellen, die SqlQuery verwendet, um die benötigten Daten zurückzugeben. Vorteile gegenüber einigen anderen Optionen sind:
Beispielcode:
public partial class myEntities
{
public List<MyClass> usp_GetTestRecords(int _p1, int _p2, string _groupId)
{
// fill out params
SqlParameter p1 = new SqlParameter("@p1", _p1);
...
obj[] parameters = new object[] { p1, p2, groupId };
// call the proc
return this.Database.SqlQuery<MyClass>(@"EXECUTE usp_GetTestRecords @p1, @p2, @groupId", parameters).ToList();
}
}
Die beste Lösung, die ich gefunden habe, ist ein wenig zu betrügen.
Kommentieren Sie in der Store-Prozedur alles, setzen Sie eine erste Zeile mit einem select [foo]='', [bar]=''
etc ... Aktualisieren Sie nun das Modell, wechseln Sie zur zugeordneten Funktion, wählen Sie den komplexen Typ aus und klicken Sie auf Get Column Information
und dann auf Create Complex Type
.
Kommentieren Sie nun die Fälschung und entkommentieren Sie den eigentlichen Geschäftsvorgang.
Während des Imports
SET FMTONLY ON Kann zur Aufnahme des sp-Schemas verwendet werden.
Wenn Sie den SP ändern und den neuen aktualisieren möchten, sollten Sie die alte definierte Funktion aus der EDMX-Datei (aus XML) löschen, da SP zwar aus dem Modellbrowser gelöscht wird, sie jedoch nicht in EDMX gelöscht wird. Zum Beispiel;
<FunctionImport Name="GetInvoiceByNumber" ReturnType="Collection(Model.Invoice_Result)">
<Parameter Name="InvoiceNumber" Mode="In" Type="Int32" />
</FunctionImport>
Ich hatte das gleiche Problem, und wenn ich den FuctionImport-Tag des entsprechenden sp total lösche, wurde das Modell richtig aktualisiert. Sie können das Tag finden, indem Sie den Funktionsnamen in Visual Studio suchen.
Ändern Sie einfach zu
ALTER PROCEDURE [dbo].[usp_GetTestRecords]
[email protected] int = 0,
[email protected] int = 0
@groupId nvarchar(10) = 0
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM CUSTOMERS WHERE Id = @groupId
END
Ich weiß, dass dies ein alter Thread ist, aber falls jemand die gleichen Probleme hat, werde ich mein Leid erzählen.
Um das Problem zu finden, führen Sie den sql-Profiler aus, wenn Sie Ihre gespeicherte Prozedur hinzufügen. Dann können Sie sehen, welches Entity-Framework als Parameter zum Generieren Ihrer Ergebnismenge übergeben wird. Ich stelle mir fast immer vor, es werden Nullparameterwerte übergeben. Wenn Sie schnell SQL erzeugen, indem Sie Zeichenfolgenwerte und Parameterwerte verketten, und einige sind null, dann bricht die SQL und es wird kein Rückgabesatz angezeigt.
Ich brauche keine temporären Tabellen oder irgendetwas, nur einen Exec-Befehl.
Ich hoffe es hilft
Möglicherweise haben Sie Glück, den Modellbrowser zu öffnen. Dann gehen Sie zu Funktionsimporte, doppelklicken Sie auf die betreffende gespeicherte Prozedur, klicken Sie dann manuell auf "Spalteninformationen abrufen" und dann auf "Neuen komplexen Typ erstellen". Dies beseitigt normalerweise das Problem.