Pregunta

¿Cómo puedo obtener un registro (y eventualmente eliminarlo) usando LINQ2SQL sin saber el tipo en el momento de la compilación?

Hasta ahora tengo

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

Pero, por supuesto, el muñeco no es un registro real, es solo un muñeco

No quiero usar SQL directo (o ejecutecomano), ya que hay una lógica comercial en la eliminación en la clase parcial de DataContext

¿Se puede hacer esto de alguna manera?

¡Muchas gracias!

EDITAR

En respuesta a Stringlinwarior, edité mi código a:

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

Esto dispara el código de deleción corrección, pero también parece tratar de agregar el registro primero a la DB, ya que obtengo una Sqlexception de que algunos campos "no nulos" están vacíos, lo que supongo que es cierto sobre el registro ficticio, como el registro, como el Lo único que esto tiene es el primario, de lo contrario, está todo vacío. Así que probé el otro código que publicaste (algo que de todos modos siempre quise tener) ¡y eso funciona excelente!

suy mi código actual:

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

Gracias

¿Fue útil?

Solución

La única forma en que puedo pensar es usar la información del modelo de la asignación de su base de datos para determinar qué miembro representa la clave principal:

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

(Estoy usando LinqPad aquí: supongo que los modelos típicos de LINQ a SQL tienen esta información de mapeo disponible).

Luego use Reflection para establecer el valor de ese miembro clave en el elemento ficticio que ha creado. Después de eso, debe conectar el muñeco a la mesa antes de tratar de eliminarlo, pasando false Como segundo parámetro para decirle a LINQ a SQL que realmente no desea actualizar el objeto usando sus valores actuales, pero que debe rastrear los cambios de aquí en adelante.

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

¿Tiene sentido?

Editar

Cuando solo elimina un objeto, no necesariamente tiene que obtener el registro de la base de datos. Si establece el valor de identificación del objeto y luego lo adjunta al contexto (como se muestra arriba), Linq a SQL lo tratará como si se recuperara de la base de datos. En ese momento, llamar a DeleteonSubmit debe decirle al contexto que construya un DELETE Declaración en SQL basado en el valor de clave principal de ese objeto.

Sin embargo, si necesita recuperar el objeto para algún propósito que no sea la eliminación, deberá construir una expresión para representar la consulta para ese objeto. Entonces, por ejemplo, si estaba escribiendo la consulta manualmente, diría algo como:

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

Entonces, para construir dinámicamente la expresión de Lambda dentro de los paréntesis, es posible que haga algo como esto:

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

Entonces necesitaría usar la reflexión para invocar el primer método genérico:

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})
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top