Domanda

Come posso prendere un record (e infine eliminarlo) usando LinQ2SQL senza conoscere il tipo a tempo di compilazione?

Finora ho

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

Ma ovviamente il manichino non è un vero disco, è solo un manichino

Non voglio usare SQL diretto (o esecuto

Questo può essere fatto in qualche modo?

grazie mille!

MODIFICARE

In risposta a StriplinWarior, ho modificato il mio codice su:

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

Questo spara dal codice di eliminazione corretto, ma sembra anche provare ad aggiungere prima il record al db, poiché ottengo una sqrexception che alcuni campi "non nulli" siano vuoti, il che immagino sia vero per il record fittizio, come il L'unica cosa che ha è il primario, altrimenti è tutto vuoto. Quindi ho provato l'altro codice che hai pubblicato (qualcosa che ho sempre voluto avere) e funziona eccellente!

suo il mio codice attuale:

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

Grazie

È stato utile?

Soluzione

L'unico modo in cui riesco a pensare è utilizzare le informazioni del modello dalla mappatura del database per capire quale membro rappresenta la chiave principale:

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()

(Sto usando LinqPad qui: presumo tipico Linq a SQL Modelli abbiano queste informazioni di mappatura disponibili.)

Quindi utilizzare la riflessione per impostare il valore di quel membro chiave sull'elemento fittizio che hai creato. Dopodiché, devi attaccare il manichino al tavolo prima di provare a eliminarlo, passando false Come secondo parametro per dire a Linq a SQL che in realtà non si desidera aggiornare l'oggetto usando i suoi valori attuali, ma che dovrebbe tracciare le modifiche da qui in poi.

tbl.Attach(dummy, false) 
tbl.DeleteOnSubmit(dummy)
db.SubmitChanges()

Ha senso?

Modificare

Quando stai eliminando solo un oggetto, non devi necessariamente ottenere il record dal database. Se si imposta il valore ID dell'oggetto e quindi lo si allega al contesto (come mostrato sopra), LINQ a SQL lo tratterà come se fosse stato recuperato dal database. A quel punto, chiamare ELETEonsubmit dovrebbe dire al contesto di costruire a DELETE Dichiarazione in SQL in base al valore della chiave primaria di quell'oggetto.

Tuttavia, se è necessario recuperare l'oggetto per uno scopo diverso dalla cancellazione, dovrai costruire un'espressione per rappresentare la query per quell'oggetto. Quindi, ad esempio, se stavi scrivendo manualmente la query, diresti qualcosa di simile:

Dim obj = tbl.First(Function(e) e.Id = ID)

Quindi, per costruire dinamicamente l'espressione di lambda all'interno delle parentesi, potresti fare qualcosa del genere:

Dim eParam = Expression.Parameter(rowType, "e")
Dim lambda = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(eParam, idMember), Expression.Constant(ID)), eParam)

Quindi dovresti usare la riflessione per invocare il primo metodo generico:

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})
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top