Schnapp linq zu SQL Record von PrimaryKey, ohne seinen Typ zu kennen
-
27-10-2019 - |
Frage
Wie kann ich einen Datensatz (und löschen sie schließlich löschen) mit linq2SQL abrufen, ohne den Typ zur Kompilierung zu kennen?
Bisher habe ich
Sub Delete(ByVal RecordType As String, ByVal ID As Integer)
Dim dummy = Activator.CreateInstance(MyAssembly, RecordType).Unwrap
Dim tbl = GetTable(dummy.GetType)
tbl.DeleteOnSubmit(dummy)
End Sub
Aber natürlich ist der Dummy keine tatsächliche Aufzeichnung, es ist nur ein Dummy
Ich möchte keine Direct SQL (oder ExecuteCommand) verwenden, da bei der Löschung in der DataContext Partial Class eine Geschäftslogik vorliegt
Kann das irgendwie getan werden?
Danke sehr!
BEARBEITEN
Als Antwort auf Striplinwarior habe ich meinen Code bearbeitet, um:
Sub Delete(ByVal RecordType As ObjectType, ByVal ID As Integer)
Dim dummy = Activator.CreateInstance(ObjectType.Account.GetType.Assembly.FullName, RecordType.ToString).Unwrap
SetObjProperty(dummy, PrimaryKeyField(RecordType), ID)
Dim tbl = GetTable(dummy.GetType)
tbl.Attach(dummy)
tbl.DeleteOnSubmit(dummy)
SubmitChanges()
End Sub
Dies schießt den Korrektur des Löschcode -Correclty ab, scheint aber auch zu versuchen, den Datensatz zuerst zur DB hinzuzufügen, da ich eine SQLEXception erhalte, dass einige "nicht null" -Felder leer sind, was ich für den Dummy -Datensatz wie die wahre Dummy -Datensatz ist Das einzige, was dies hat, ist der Primärkey, sonst ist alles leer. Also habe ich den anderen Code ausprobiert, den du gepostet hast (etwas, das ich sowieso schon immer haben wollte) und das funktioniert ausgezeichnet!
Ihre mein aktueller Code:
Function LoadRecord(ByVal RecordType As String, ByVal RecordID As Integer) As Object
Dim dummy = Activator.CreateInstance(AssemblyName, RecordType).Unwrap
Dim rowType = dummy.GetType
Dim eParam = Expression.Parameter(rowType, "e")
Dim idm = rowType.GetProperty(PrimaryKeyField(RecordType))
Dim lambda = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(eParam, idm), Expression.Constant(RecordID)), eParam)
Dim firstMethod = GetType(Queryable).GetMethods().[Single](Function(m) m.Name = "Single" AndAlso m.GetParameters().Count() = 2).MakeGenericMethod(rowType)
Dim tbl = GetTable(rowType)
Dim obj = firstMethod.Invoke(Nothing, New Object() {tbl, lambda})
Return obj
End Function
Sub Delete(ByVal RecordType As String, ByVal RecordID As Integer)
Dim obj = LoadRecord(RecordType, RecordID)
Dim tbl = GetTable(obj.GetType)
tbl.DeleteOnSubmit(obj)
SubmitChanges()
End Sub
Danke
Lösung
Die einzige Möglichkeit, wie ich mir vorstellen kann, besteht darin, die Modellinformationen aus Ihrer Datenbankzuordnung zu verwenden, um herauszufinden, welches Mitglied den Primärschlüssel darstellt:
Dim primaryKey = (From t In db.Mapping.GetTables() _
Where t.RowType.Type = tableType _
Let keyMember = (From dm In t.RowType.DataMembers where dm.IsPrimaryKey).FirstOrDefault() _
Select keyMember.Member.Name).First()
(Ich verwende hier Linqpad: Ich gehe davon aus, dass typische Linq zu SQL -Modellen diese Zuordnungsinformationen verfügbar haben.)
Verwenden Sie dann Reflection, um den Wert dieses Schlüsselelements auf dem von Ihnen erstellten Dummy -Element festzulegen. Danach müssen Sie den Dummy an den Tisch befestigen, bevor Sie versuchen, sie zu löschen false
Als zweiter Parameter, der SQL zu Linq anweist, möchten Sie das Objekt nicht mit seinen aktuellen Werten aktualisieren, aber dass es Änderungen von hier an verfolgen sollte.
tbl.Attach(dummy, false)
tbl.DeleteOnSubmit(dummy)
db.SubmitChanges()
Ist das sinnvoll?
Bearbeiten
Wenn Sie nur ein Objekt löschen, müssen Sie nicht unbedingt den Datensatz aus der Datenbank erhalten. Wenn Sie den ID -Wert des Objekts festlegen und dann an den Kontext anhängen (wie oben gezeigt), behandelt LINQ ihn so, als würde er aus der Datenbank abgerufen. Zu diesem Zeitpunkt sollte das Aufrufen von Deleteonsubmit den Kontext mitteilen, dass er a konstruieren soll DELETE
Anweisung in SQL basierend auf dem primären Schlüsselwert dieses Objekts.
Wenn Sie das Objekt jedoch für einen anderen Zweck als das Löschen abrufen müssen, müssen Sie einen Ausdruck konstruieren, um die Abfrage für dieses Objekt darzustellen. Wenn Sie beispielsweise die Abfrage manuell schreiben würden, würden Sie so etwas sagen wie:
Dim obj = tbl.First(Function(e) e.Id = ID)
Um den Lambda -Ausdruck dynamisch in den Klammern zu erstellen, können Sie so etwas tun:
Dim eParam = Expression.Parameter(rowType, "e")
Dim lambda = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(eParam, idMember), Expression.Constant(ID)), eParam)
Dann müssten Sie Reflexion verwenden, um die generische erste Methode aufzurufen:
Dim firstMethod = GetType(Queryable).GetMethods().[Single](Function(m) m.Name = "Single" AndAlso m.GetParameters().Count() = 2).MakeGenericMethod(rowType)
Dim obj = firstMethod.Invoke(Nothing, New Object() {tbl, lambda})