如何使用LINQ按字符串名称连接表

时间:2016-07-25 20:45:16

标签: c# sql-server linq linq-to-sql

我正在将一些包含基于文本的查询的代码更新到基于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)中BladeBlades的定义

<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模型。

4 个答案:

答案 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 };
}