【问题标题】:Dynamically set the table name in LINQ query在 LINQ 查询中动态设置表名
【发布时间】:2018-10-19 03:36:53
【问题描述】:

我正在研究数据仓库应用程序,我们有 4 个架构相同的表。这些表之间的唯一区别只是表名。

表格示例:

  • ps_Contractor
  • ps_Employee
  • ps_Union
  • ps_NonUnion

架构

  • 身份证
  • 每小时
  • 好处
  • 总计

现在我需要根据这些表格生成 4 个报告。我不想编写 4 个单独的 LINQ 查询,而是编写一个可以动态传递表名的查询。

问题如何在以下 LINQ 查询中动态传递表名?

var data = ( from q in _dbcontext.ps_Contractor 
join _l in _dbcontext.log on q.id equals l.tablelogid 
where q.hourly = 8
select new{
 hourly=q.hourly,
 benefit=q.benefit,
 total=q.total,
 log = l.message
}.ToList();

我查看了堆栈溢出提出的所有类似问题。我不想使用 ExecuteStoreQuery。

我有什么选择?

【问题讨论】:

  • 在讨论 X 和 Y 之前,我相信在未来创建四个单独的 LINQ 查询时的可读性/可维护性有很多优点。这四种方法可能比通过创建一个通用函数来节省代码重复更有价值。
  • stackoverflow.com/questions/3428069/…我真的不会因为只有4个重复而达到这样的程度,现在如果我们更像是说40个重复,那么我的观点可能会改变。
  • 也许你可以按照他们在这里的建议stackoverflow.com/questions/12455389/…

标签: c# linq entity-framework


【解决方案1】:

如果所有表都有相同的列,那么我会从这些表中提取一个interface 并创建partial entity classes 只是为了实现该接口,最后使用该接口进行查询。

例如:

//entities
public partial class ps_Contractor: ICommonInterface{}
public partial class Table2 : ICommonInterface{}

在搜索方法中,我会通过 IEnumerable<ICommonInterface>IQueryable<ICommonInterface> 并在其上应用该查询。您需要做的就是将不同的表传递给该搜索方法。 或者你甚至可以拥有ICommonInterface 类型的泛型类并使用它来进行查询。

public void Example(IQueryable<ICommonInterface>dataSource)
{
var data = ( from q in dataSource 
join _l in _dbcontext.log on q.id equals l.tablelogid 
where q.hourly = 8
select new{
 hourly=q.hourly,
 benefit=q.benefit,
 total=q.total,
 log = l.message
}.ToList();
}

Example(_dbcontext.ps_Contractor.AsQueryable())

这只是我现在测试的一个示例:

 public class Repository
{
    private List<string> GetData(IQueryable<IContractor> data)
    {
        return (from d in data select d.Name).ToList();
    }

    public List<string> GetFullTime()
    {
        using (var context = new TestDbEntities())
        {
            return GetData(context.FTContractors.AsQueryable());
        }
    }

    public List<string> GetPartTime()
    {
        using (var context = new TestDbEntities())
        {
            return GetData(context.PTContractors.AsQueryable());
        }
    }
}

实体:

public interface IContractor
    {
        int Id { get; set; }
        string Name { get; set; }
    }

    public partial class FTContractor : IContractor
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
public partial class PTContractor : IContractor
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

测试:

[TestMethod]
        public void Temp()
        {
            var tester = new Repository();

            var ft = tester.GetFullTime();
            var pt = tester.GetPartTime();

             Assert.AreEqual(3, ft.Count);
             Assert.AreEqual(4, pt.Count);
        }

在数据库中有两个表只包含 IdName

【讨论】:

  • 您应该尝试在一个工​​作示例中解决这个问题。我看不出您如何“使用该界面进行查询”。 EF 不支持接口作为 LINQ 语句中的泛型参数。
  • @GertArnold,我并没有真正使用该接口进行查询,而是您使用它只是为了能够访问属性来编写查询。
【解决方案2】:

EF Core 不再有一个非通用的 .set 方法,但是这个扩展类可以很容易地使用动态 Linq 基于字符串查询你的表

public static class DbContextExtensions
{
    public static IQueryable<Object> Set(this DbContext _context, Type t)
    {
        return (IQueryable<Object>)_context.GetType().GetMethod("Set").MakeGenericMethod(t).Invoke(_context, null);
    }


    public static IQueryable<Object> Set(this DbContext _context, String table)
    {
        Type TableType = _context.GetType().Assembly.GetExportedTypes().FirstOrDefault(t => t.Name == table);
        IQueryable<Object> ObjectContext = _context.Set(TableTypeDictionary[table]);
        return ObjectContext;
    }
}

}

用法:

IQueryable<Object> query = db.Set("TableName");
// Filter against "query" variable below...
List<Object> result = query.ToList();
// or use further dynamic Linq
IQueryable<Object> query = db.Set("TableName").Where("t => t.TableFilter == \"MyFilter\"");

【讨论】:

    猜你喜欢
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 2014-01-07
    • 1970-01-01
    • 2012-11-11
    • 2010-10-13
    • 2013-10-11
    相关资源
    最近更新 更多