我正在将一些包含基于文本的查询的代码更新到基于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);
我遇到了一个问题,即加入的表是由C#中的字符串指定的。 strDeviceType
的可能值为" Blade"," Engine"," Diode" (以及更多),这些表都包含在我的LINQ-to-SQL模型中。
这是一个专门加入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 };
}
如何用正确的集合替换... in dc.Blades ...
?即如何从字符串" Blade"到模型中名为Blades
的集合?
以下是自动生成模型(vb.net)中Blade
和Blades
的定义
<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
其他表的定义相似。它们还有字段ID,Name - 但它们都没有基类或接口,它们保证了这些属性。
修改
我原本应该包括我的意图是使这个查询适应将来添加的具有ID,Name的表,这些表将以类似的方式使用,而无需重新编译它所在的项目。具有linq-to的项目添加表时,可以轻松地重新编译-sql模型。
答案 0 :(得分:1)
不,你不能像使用字符串查询那样做,因为在这种情况下你会失去静态类型的安全性。您可以包含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 };
}
}
答案 1 :(得分:0)
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,
}
答案 2 :(得分:0)
假设Test.ID在Blade,Engine和Diode中是唯一的,你可以在查询中做的是检查每个表是否存在,然后连接是否匹配:
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 : "")
}
);
}
答案 3 :(得分:0)
我找到了扩展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 };
}