захватывайте запись linq to sql с помощью primarykey, не зная ее типа

StackOverflow https://stackoverflow.com/questions/4853530

  •  27-10-2019
  •  | 
  •  

Вопрос

как я могу получить запись (и в конечном итоге удалить ее) с помощью linq2sql, не зная типа во время компиляции?

пока что у меня есть

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

но, конечно, манекен не является реальной записью, это просто манекен

я не хочу использовать прямой sql (или executecommand), поскольку при удалении в частичном классе datacontext выполняется бизнес-логика

можно ли это как-то сделать?

большое вам спасибо!

Редактировать

в ответ на striplinwarior я отредактировал свой код, чтобы:

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

это запускает корректность кода удаления, но также, похоже, пытается сначала добавить запись в базу данных, поскольку я получаю sqlexception о том, что некоторые поля "not null" пусты, что, я думаю, верно для фиктивной записи, поскольку единственное, что у этого есть, это primarykey, остальное все пустое.итак, я попробовал другой опубликованный вами код (то, что я в любом случае всегда хотел иметь), и это работает отлично!

это мой текущий код:

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

Спасибо

Это было полезно?

Решение

Единственный способ, который я могу придумать, - это использовать информацию о модели из сопоставления вашей базы данных, чтобы выяснить, какой элемент представляет первичный ключ:

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

(Здесь я использую LINQPad:Я предполагаю, что типичные модели LINQ to SQL имеют доступ к этой информации о сопоставлении.)

Затем используйте отражение, чтобы установить значение этого ключевого элемента для созданного вами фиктивного элемента.После этого вам нужно прикрепить манекен к таблице, прежде чем пытаться удалить его, передав false в качестве второго параметра, сообщающего LINQ to SQL, что на самом деле вы не хотите обновлять объект, используя его текущие значения, но что с этого момента он должен отслеживать изменения.

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

Есть ли в этом смысл?

Редактировать

Когда вы только удаляете объект, вам не обязательно получать запись из базы данных.Если вы зададите значение ID объекта, а затем присоедините его к контексту (как показано выше), LINQ to SQL будет обрабатывать его так, как если бы он был извлечен из базы данных.В этот момент вызов DeleteOnSubmit должен сообщить контексту о необходимости создания DELETE оператор в SQL, основанный на значении первичного ключа этого объекта.

Однако, если вам нужно извлечь объект для какой-либо цели, отличной от удаления, вам нужно будет создать выражение для представления запроса к этому объекту.Так, например, если бы вы писали запрос вручную, вы бы сказали что-то вроде:

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

Итак, чтобы динамически построить лямбда-выражение внутри круглых скобок, вы могли бы сделать что-то вроде этого:

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

Затем вам нужно будет использовать отражение для вызова общего первого метода:

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})
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top