Linq to sql 在不知道其类型的情况下,通过primarykey获取linq到sql记录

Linq to sql 在不知道其类型的情况下,通过primarykey获取linq到sql记录,linq-to-sql,delete-record,Linq To Sql,Delete Record,如何使用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

如何使用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,即一些“notnull”字段为空,我猜这对于伪记录是正确的,因为它只有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到SQL模型具有此映射信息。)

然后使用反射在您创建的虚拟项上设置该关键成员的值。在这之后,您需要在尝试删除该虚拟对象之前将其附加到表中,并将
false
作为第二个参数传递给LINQ to SQL,以告知您实际上不想使用其当前值更新该对象,但它应该从此处开始跟踪更改

tbl.Attach(dummy, false) 
tbl.DeleteOnSubmit(dummy)
db.SubmitChanges()
这有意义吗

编辑

当您只删除一个对象时,不一定要从数据库中获取记录。如果设置对象的ID值,然后将其附加到上下文(如上所示),linqtosql将把它当作是从数据库检索的。此时,调用DeleteOnSubmit应该告诉上下文根据对象的主键值在SQL中构造一个
DELETE
语句

但是,如果需要出于删除以外的目的检索对象,则需要构造一个表达式来表示该对象的查询。因此,例如,如果您手动编写查询,您会说:

Dim obj = tbl.First(Function(e) e.Id = ID)
因此,要在括号内动态构建lambda表达式,可以执行以下操作:

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

我能想到的唯一方法是使用数据库映射中的模型信息来确定哪个成员代表主键:

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到SQL模型具有此映射信息。)

然后使用反射在您创建的虚拟项上设置该关键成员的值。在这之后,您需要在尝试删除该虚拟对象之前将其附加到表中,并将
false
作为第二个参数传递给LINQ to SQL,以告知您实际上不想使用其当前值更新该对象,但它应该从此处开始跟踪更改

tbl.Attach(dummy, false) 
tbl.DeleteOnSubmit(dummy)
db.SubmitChanges()
这有意义吗

编辑

当您只删除一个对象时,不一定要从数据库中获取记录。如果设置对象的ID值,然后将其附加到上下文(如上所示),linqtosql将把它当作是从数据库检索的。此时,调用DeleteOnSubmit应该告诉上下文根据对象的主键值在SQL中构造一个
DELETE
语句

但是,如果需要出于删除以外的目的检索对象,则需要构造一个表达式来表示该对象的查询。因此,例如,如果您手动编写查询,您会说:

Dim obj = tbl.First(Function(e) e.Id = ID)
因此,要在括号内动态构建lambda表达式,可以执行以下操作:

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

你好我知道如何获取primarykey字段的名称。我想出来了。但是一旦我有了这个字段的名称,我怎么才能得到这个记录呢。这就是问题所在。谢谢。@Yisman:我用原来的策略解决了问题,并相应地更新了代码。您需要将
false
作为第二个参数传递给
Attach
,以告知LINQ to SQL该项未被更新。与第二种方法相比,第一种方法的优点是它避免了到数据库的额外往返(往返非常昂贵)。您甚至可以通过这种方式在一次往返中删除多个项目。您好。我知道如何获取primarykey字段的名称。我想出来了。但是一旦我有了这个字段的名称,我怎么才能得到这个记录呢。这就是问题所在。谢谢。@Yisman:我用原来的策略解决了问题,并相应地更新了代码。您需要将
false
作为第二个参数传递给
Attach
,以告知LINQ to SQL该项未被更新。与第二种方法相比,第一种方法的优点是它避免了到数据库的额外往返(往返非常昂贵)。您甚至可以通过这种方式在一次往返中删除多个项目。