如何使用 LINQ 按字符串名称加入 table
How to join table by string name using LINQ
我正在将一些包含基于文本的查询的代码更新为基于 LINQ 的查询。
在这个例子中,
var strDeviceType = "Blade";
// code edited for brevity
var strQuery = String.Format(
" SELECT Test.ID, {0}.Name AS Device " +
" FROM Test " +
" INNER JOIN {0} ON DeviceID = {0}.ID ", strDeviceType);
我遇到了一个问题运行,就是被连接的table是由C#中的一个字符串指定的。 strDeviceType
的可能值是 "Blade"、"Engine"、"Diode"(以及更多),这些 table 都包含在我的 LINQ-to-SQL型号.
这是一个专门加入 Blade table 的查询
using (MyDataContext dc = new MyDataContext())
{
var result = from test in dc.Tests
join blade in dc.Blades on test.DeviceID equals blade.ID
select new { test.ID, blade.Name };
}
如何将 ... in dc.Blades ...
替换为正确的集合?即我如何从字符串 "Blade" 到模型中名为 Blades
的集合?
这里是自动生成模型中Blade
和Blades
的定义(vb.net)
<Global.System.Data.Linq.Mapping.TableAttribute(Name:="dbo.Blade")> _
Partial Public Class Blade
Implements System.ComponentModel.INotifyPropertyChanging,
System.ComponentModel.INotifyPropertyChanged
' ...
Public ReadOnly Property Blades() As System.Data.Linq.Table(Of Blade)
Get
Return Me.GetTable(Of Blade)
End Get
End Property
其他table的定义类似。它们也有字段 ID、名称 - 但没有它们共享的基础 class 或接口来保证这些属性。
编辑
我本来应该包括我的意图是让这个查询适应未来添加的带有 ID、名称的 tables,它们将以类似的方式使用,而无需重新编译它所在的项目。使用 linq-to-sql 模型的项目可以在添加 tables 时轻松重新编译。
不,您不能像处理字符串查询那样执行此操作,因为在这种情况下您会失去静态类型安全性。您可以包含一个 if..else
条件,并根据该评估更改集合以加入
if(strDeviceType == "Blade")
{
using (MyDataContext dc = new MyDataContext())
{
var result = from test in dc.Tests
join blade in dc.Blades on test.DeviceID equals blade.ID
select new { test.ID, blade.Name };
}
}
else
{
using (MyDataContext dc = new MyDataContext())
{
var result = from test in dc.Tests
join engine in dc.Engine on test.DeviceID equals engine.ID
select new { test.ID, engine.Name };
}
}
public class Device
{
[Key]
public int ID { get; set; }
public int Name { get; set; }
// if it must be a string, you can use this.
// public string Type{ get; set; }
//I personally prefer this approach
public DeviceType Type { get; set; }
}
public enum DeviceType
{
Blade = 1,
Engine = 2,
Diode = 3,
}
假设 Test.ID 在 Blade、Engine 和 Diode 中是唯一的,您可以在查询中做的是检查每个 table 是否存在,然后连接是否匹配:
using (MyDataContext dc = new MyDataContext())
{
var result =
(from test in dc.Tests
let blade = (from t in dc.Blade where t.id == test.DeviceID)
let engine = (from t in dc.Engine where t.id == test.DeviceID)
let diode = (from t in dc.Diode where t.id == test.DeviceID)
select new {
test.ID,
Device =
(blade.Count() > 0 ? blade.FirstOrDefault().Name : "") +
(engine.Count() > 0 ? engine.FirstOrDefault().Name : "") +
(diode.Count() > 0 ? diode.FirstOrDefault().Name : "")
}
);
}
我找到了一种方法来扩展 linq-to-sql 类 以实现通用接口,并在答案 here 的 linq 查询中使用该接口。这是有效的,因为 linq-to-sql 类 被标记为 partial
。添加更多表时,只需要重新编译数据上下文项目,这是设计人员无论如何都需要的。我使用反射通过复数名称在 linq-to-sql 模型中找到 Table<TEntity>
属性。
我在 linq-to-sql 模型旁边添加了一个 vb 文件,代码如下:
Public Interface IDeviceTable
Property ID() As Long
Property Name() As String
End Interface
Partial Public Class Blade
Implements IDeviceTable
Public Property ID1 As Long Implements IDeviceTable.ID
Get
Return Me.ID
End Get
Set(value As Long)
Me.ID = value
End Set
End Property
Public Property Name1 As String Implements IDeviceTable.Name
Get
Return Me.Name
End Get
Set(value As String)
Me.Name = value
End Set
End Property
End Class
Partial Public Class Diode
Implements IDeviceTable
' etc.
End Class
并更改了查询:
using (TeradiodeDataContext dc = new TeradiodeDataContext())
{
var strDeviceType = "Blade";
var pluralDeviceType = System.Data.Entity.Design.PluralizationServices.
PluralizationService.CreateService(Application.CurrentCulture).
Pluralize(strDeviceType);
var devices = (System.Data.Linq.Table<IDeviceTable>)dc.GetType().
GetProperty(pluralDeviceType).GetValue(dc);
var result = from test in dc.Tests
join blade in devices on test.DeviceID equals blade.ID
select new { test.ID, blade.Name };
}
我正在将一些包含基于文本的查询的代码更新为基于 LINQ 的查询。
在这个例子中,
var strDeviceType = "Blade";
// code edited for brevity
var strQuery = String.Format(
" SELECT Test.ID, {0}.Name AS Device " +
" FROM Test " +
" INNER JOIN {0} ON DeviceID = {0}.ID ", strDeviceType);
我遇到了一个问题运行,就是被连接的table是由C#中的一个字符串指定的。 strDeviceType
的可能值是 "Blade"、"Engine"、"Diode"(以及更多),这些 table 都包含在我的 LINQ-to-SQL型号.
这是一个专门加入 Blade table 的查询
using (MyDataContext dc = new MyDataContext())
{
var result = from test in dc.Tests
join blade in dc.Blades on test.DeviceID equals blade.ID
select new { test.ID, blade.Name };
}
如何将 ... in dc.Blades ...
替换为正确的集合?即我如何从字符串 "Blade" 到模型中名为 Blades
的集合?
这里是自动生成模型中Blade
和Blades
的定义(vb.net)
<Global.System.Data.Linq.Mapping.TableAttribute(Name:="dbo.Blade")> _
Partial Public Class Blade
Implements System.ComponentModel.INotifyPropertyChanging,
System.ComponentModel.INotifyPropertyChanged
' ...
Public ReadOnly Property Blades() As System.Data.Linq.Table(Of Blade)
Get
Return Me.GetTable(Of Blade)
End Get
End Property
其他table的定义类似。它们也有字段 ID、名称 - 但没有它们共享的基础 class 或接口来保证这些属性。
编辑
我本来应该包括我的意图是让这个查询适应未来添加的带有 ID、名称的 tables,它们将以类似的方式使用,而无需重新编译它所在的项目。使用 linq-to-sql 模型的项目可以在添加 tables 时轻松重新编译。
不,您不能像处理字符串查询那样执行此操作,因为在这种情况下您会失去静态类型安全性。您可以包含一个 if..else
条件,并根据该评估更改集合以加入
if(strDeviceType == "Blade")
{
using (MyDataContext dc = new MyDataContext())
{
var result = from test in dc.Tests
join blade in dc.Blades on test.DeviceID equals blade.ID
select new { test.ID, blade.Name };
}
}
else
{
using (MyDataContext dc = new MyDataContext())
{
var result = from test in dc.Tests
join engine in dc.Engine on test.DeviceID equals engine.ID
select new { test.ID, engine.Name };
}
}
public class Device
{
[Key]
public int ID { get; set; }
public int Name { get; set; }
// if it must be a string, you can use this.
// public string Type{ get; set; }
//I personally prefer this approach
public DeviceType Type { get; set; }
}
public enum DeviceType
{
Blade = 1,
Engine = 2,
Diode = 3,
}
假设 Test.ID 在 Blade、Engine 和 Diode 中是唯一的,您可以在查询中做的是检查每个 table 是否存在,然后连接是否匹配:
using (MyDataContext dc = new MyDataContext())
{
var result =
(from test in dc.Tests
let blade = (from t in dc.Blade where t.id == test.DeviceID)
let engine = (from t in dc.Engine where t.id == test.DeviceID)
let diode = (from t in dc.Diode where t.id == test.DeviceID)
select new {
test.ID,
Device =
(blade.Count() > 0 ? blade.FirstOrDefault().Name : "") +
(engine.Count() > 0 ? engine.FirstOrDefault().Name : "") +
(diode.Count() > 0 ? diode.FirstOrDefault().Name : "")
}
);
}
我找到了一种方法来扩展 linq-to-sql 类 以实现通用接口,并在答案 here 的 linq 查询中使用该接口。这是有效的,因为 linq-to-sql 类 被标记为 partial
。添加更多表时,只需要重新编译数据上下文项目,这是设计人员无论如何都需要的。我使用反射通过复数名称在 linq-to-sql 模型中找到 Table<TEntity>
属性。
我在 linq-to-sql 模型旁边添加了一个 vb 文件,代码如下:
Public Interface IDeviceTable
Property ID() As Long
Property Name() As String
End Interface
Partial Public Class Blade
Implements IDeviceTable
Public Property ID1 As Long Implements IDeviceTable.ID
Get
Return Me.ID
End Get
Set(value As Long)
Me.ID = value
End Set
End Property
Public Property Name1 As String Implements IDeviceTable.Name
Get
Return Me.Name
End Get
Set(value As String)
Me.Name = value
End Set
End Property
End Class
Partial Public Class Diode
Implements IDeviceTable
' etc.
End Class
并更改了查询:
using (TeradiodeDataContext dc = new TeradiodeDataContext())
{
var strDeviceType = "Blade";
var pluralDeviceType = System.Data.Entity.Design.PluralizationServices.
PluralizationService.CreateService(Application.CurrentCulture).
Pluralize(strDeviceType);
var devices = (System.Data.Linq.Table<IDeviceTable>)dc.GetType().
GetProperty(pluralDeviceType).GetValue(dc);
var result = from test in dc.Tests
join blade in devices on test.DeviceID equals blade.ID
select new { test.ID, blade.Name };
}