如何使用LINQ动态查询不同的表

本文关键字:查询 何使用 LINQ 动态 | 更新日期: 2023-09-27 18:29:51

所以我不确定你是否能做到这一点,但如果可以的话,我希望避免使用SQL字符串。我想用Linq/DbContexts做的是使用SQL可以轻松完成的以下操作:

string sql = "UPDATE " + tableName + " SET Status=0 WHERE Id=" + formId.ToString();

我可以很容易地将其放入一个循环中,其中tableName和formId是动态给定的,执行起来没有问题。

我有多个DbContext,所以我不知道有什么方法可以做这样的事情:

var db = new *dynamicallyChosenContext*()
var query = from p in db.*dynamicallyChosenAlso*
            where p.Id == formId
            select p;
foreach (var result in query)
{
    result.Status = 0;
}
db.SaveChanges()

谢谢你的帮助!

如何使用LINQ动态查询不同的表

这里有一段工作代码,可以在运行时从不同的上下文更新不同的表,而无需使用反射。

namespace DemoContexts
{
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;

    public interface IThing
    {
        int Id { get; set; }
        int Status { get; set; }
    }
    public class FirstPersonThing : IThing
    {
        [System.ComponentModel.DataAnnotations.Key]
        public int Id { get; set; }
        public int Status { get; set; }
        public string Foo { get; set; }
    }
    public class SecondPersonThing : IThing
    {
        [System.ComponentModel.DataAnnotations.Key]
        public int Id { get; set; }
        public int Status { get; set; }
        public string Bar { get; set; }
    }
    public class FirstContext : DbContext
    {
        public FirstContext() : base("FirstContext") { }
        public DbSet<FirstPersonThing> MyThings { get; set; }
        public DbSet<SecondPersonThing> YourThings { get; set; }
    }
    public class SecondContext : DbContext
    {
        public SecondContext() : base("SecondContext") { }
        public DbSet<FirstPersonThing> MyThings { get; set; }
        public DbSet<SecondPersonThing> YourThings { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int contextType = 1;
            int thingType = 1;
            DbContext db = RunTimeCreatedContext(contextType);
            IQueryable<IThing> collection = RunTimeCreatedCollection(db, thingType);
            UpdateRuntimeDeterminedThings(db, collection, 1);
            Console.ReadLine();
        }
        public static void UpdateRuntimeDeterminedThings(DbContext db, 
                                               IQueryable<IThing> collection, 
                                               int formId)
        {
            var querySet = collection.Where(p => p.Id == formId).ToList();
            foreach (var result in querySet)
            {
                result.Status = 0;
            }
            db.SaveChanges();
        }
        static DbContext RunTimeCreatedContext(int contextType)
        {
            if (contextType == 0)
            {
                return new FirstContext();
            }
            else
            {
                return new SecondContext();
            }
        }
        static IQueryable<IThing> RunTimeCreatedCollection(DbContext db, int thingType)
        {
            if (thingType == 0)
            {
                return db.Set(typeof(FirstPersonThing)) as IQueryable<IThing>;
            }
            else
            {
                return db.Set<SecondPersonThing>();
            }
        }
    }
}

首先要注意的是,所有这些都是静态类型的,因此要对不同类型的对象执行通用查询,这些对象必须具有公共属性签名,并且这在概念上表示在IThing接口中。

需要注意的第二件事是如何生成IQueryable。它在第一个实例中由DbContext.Set Method (Type)生成(对于FirstPersonThings),在第二个实例中则由DbContext.Set<TEntity> Method生成。第一种使用在运行时确定的类型并需要强制转换(但在运行时使用传递类型可能很有用),第二种使用泛型并在编译时确定类型。显然,还有许多其他方式可以实现此功能。

最后,UpdateRuntimeDeterminedThings方法之所以有效,是因为它使用了跨类型共享的属性和方法(通过基类型/继承或通过接口的实现)。

所有这些实际上都不是动态编程(使用动态类型是可能的),我使用了术语"运行时确定"而不是"动态"来描述这是如何工作的。

函数式编程中有一种叫做Currying的技术,您可以根据需要传递任意多的参数,这样您就可以访问它们。以下是一个示例:http://blogs.msdn.com/b/sriram/archive/2005/08/07/448722.aspx

p.S:您可以使用currying函数来迭代您的DBContexts。

如果您想使用"code"而不是sql字符串,我认为您必须使用反射。C#就是这样工作的。。。这就是你可以做到的:

using System;
using System.Data.Entity;
using System.Linq;
public class TestContext : DbContext
{
    public DbSet<Box> Boxes { get; set; }
    public DbSet<Thing> Things { get; set; }
}
public abstract class Base
{
    public int Id { get; set; }
}
public class Box : Base
{
    public string Title { get; set; }
}
public class Thing : Base
{
    public string Name { get; set; }
}
internal class Program
{
    private static void Main(string[] args)
    {
        var db = new TestContext();
        DoIt(GetPropValue(db, "Boxes") as IQueryable<Base>);
        DoIt(GetPropValue(db, "Things") as IQueryable<Base>);
    }
    private static void DoIt(IQueryable<Base> b)
    {
        Console.WriteLine(
            b.Single(t => t.Id == 1).Id);
    }
    private static object GetPropValue(object src, string propName)
    {
        return src.GetType().GetProperty(propName).GetValue(src, null);
    }
}

很明显,你可以把字符串放在一个列表中等等,不管你需要什么。