在不知道其类型的情况下通过主键获取 linq to sql 记录
在编译时不知道类型的情况下,如何使用 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 (或执行命令),因为在 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”字段是空的,我猜这对于虚拟记录来说是正确的,因为它唯一的就是主键,其他都是空的。所以我尝试了你发布的其他代码(无论如何我一直想要的东西)并且效果非常好!
她是我当前的代码:
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
谢谢
how can i grab a record (and eventually delete it) using linq2sql without knowing the type at compile time?
so far i've got
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
but of course the dummy is not an actual record, its just a dummy
i don't want to use direct sql (or executecommand) as there's business logic going on at deletion in the datacontext partial class
can this be done somehow?
thank you very much!
EDIT
in response to striplinwarior, i edited my code to:
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
this does fire off the deletion code correclty, but also seems to try to add the record first to the db, as i get a sqlexception that some "not null" fields are empty, which i guess is true about the dummy record, as the only thing this has is the primarykey, else is all empty. so i tried the other code u posted (something i anyways always wanted to have) and that works excellent!
hers my current 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
Thank You
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我能想到的唯一方法是使用数据库映射中的模型信息来确定哪个成员代表主键:(
我在这里使用 LinqPad:我假设典型的 LINQ to SQL 模型具有可用的映射信息。)
然后使用反射在您创建的虚拟项目上设置该关键成员的值。之后,您需要在尝试删除该虚拟对象之前将其附加到表,并传递
false
作为第二个参数,以告诉 LINQ to SQL 您实际上并不希望使用其当前值来更新该对象。值,但它应该从现在开始跟踪变化。这有道理吗?
编辑
当您仅删除对象时,不一定需要从数据库中获取记录。如果设置对象的 ID 值,然后将其附加到上下文(如上所示),LINQ to SQL 会将其视为从数据库检索的对象。此时,调用DeleteOnSubmit 应该告诉上下文根据该对象的主键值在SQL 中构造一个
DELETE
语句。但是,如果您需要出于删除以外的其他目的检索对象,则需要构造一个表达式来表示对该对象的查询。因此,例如,如果您手动编写查询,您会这样说:
因此,要在括号内动态构建 lambda 表达式,您可能会执行以下操作:
然后您需要使用反射来调用通用 First 方法:
The only way I can think of is to use the model information from your database mapping to figure out which member represents the primary key:
(I'm using LinqPad here: I assume typical LINQ to SQL models have this mapping information available.)
Then use reflection to set the value of that key member on the dummy item you've created. After that, you need to attach the dummy to the table before trying to delete it, passing
false
as a second parameter to tell LINQ to SQL that you don't actually want to update the object using its current values, but that it should track changes from here on.Does that make sense?
Edit
When you're only deleting an object, you don't necessarily have to get the record from the database. If you set the ID value of the object and then attach it to the context (as shown above), LINQ to SQL will treat it as if it were retrieved from the database. At that point, calling DeleteOnSubmit should tell the context to construct a
DELETE
statement in SQL based on that object's primary key value.However, if you need to retrieve the object for some purpose other than deletion, you'll need to construct an expression to represent the query for that object. So, for example, if you were writing the query manually, you would say something like:
So to dynamically build the lambda expression inside the parentheses, you might do something like this:
Then you would need to use reflection to invoke the generic First method: