如何在LINQ中加入未知数量的列表

jas*_*son 12 c# linq sql-server

我有三个不同类型的列表:

List<Customer> customerList = new List<Customer>();
List<Product> productList = new List<Product>();
List<Vehicle> vehicleList = new List<Vehicle>();
Run Code Online (Sandbox Code Playgroud)

我也有这个清单

List<string> stringList = {"AND","OR"};
Run Code Online (Sandbox Code Playgroud)

由于第一个元素stringList是AND我想用customerList和做内连接productList.然后我想vehicleList 与结果进行正确的连接,例如:

from cust in customerList 
join prod in productList on cust.ProductId equals prod.Id
join veh in vehicleList on prod.VehicleId equals veh.Id into v
from veh in v.DefaultIfEmpty()
select new {customerName = cust.Name, customerVehicle=veh.VehicleName}
Run Code Online (Sandbox Code Playgroud)

我想以自动化的方式制作它,假设我有N多个列表和s和s的N-1数量,我该如何加入它们?此外,可以有许多相同类型的列表.这样的事情甚至可能吗?如果不是我能做些什么来使它更接近我的需要?提前致谢.ANDOR

编辑:我在这样的字典中持有列表及其类型:

var listDict = new Dictionary<Type, object>();
Run Code Online (Sandbox Code Playgroud)

所以如果有必要,我可以在这个字典里面迭代.

dja*_*azz 5

更新5-15-17:

仅仅为了回顾一下我提出的建议是我们想要的一个例子:

  1. 传入N个Table对象的列表.
  2. 传入如何加入它们的N-1连接条款列表.EG:您有2个表需要一个连接,3个需要2个,依此类推.
  3. 我们希望传入一个谓词来上下链以缩小范围.

我建议的是在SQL中完成所有这些操作并将SQL解析为可以解析的xml对象.然而,为了使它更容易处理XML序列化,让我们坚持使用基本上是一个或多个值传递的字符串.假设我们有一个结构偏离上面这样:

/*
CREATE TABLE Customer ( Id INT IDENTITY, CustomerName VARCHAR(64), ProductId INT)
INSERT INTO Customer VALUES ('Acme', 1),('Widgets', 2)
CREATE TABLE Product (Id INT IDENTITY, ProductName VARCHAR(64), VehicleId INT)
Insert Into Product Values ('Shirt', 1),('Pants', 2)
CREATE TABLE VEHICLE (Id INT IDENTITY, VehicleName VARCHAR(64))
INSERT INTO dbo.VEHICLE VALUES ('Car'),('Truck')

CREATE TABLE Joins (Id INT IDENTITY, OriginTable VARCHAR(32), DestinationTable VARCHAR(32), JoinClause VARCHAR(32))
INSERT INTO Joins VALUES ('Customer', 'Product', 'ProductId = Id'),('Product', 'Vehicle', 'VehicleId = Id')

--Data as is if I joined all three tables
CustomerId  CustomerName    ProductId   ProductName VehicleId   VehicleName
1   Acme    1   Shirt   1   Car
2   Widgets 2   Pants   2   Truck
*/
Run Code Online (Sandbox Code Playgroud)

这种结构非常简单,一切都是一对一的关键关系,而它可能有一些其他的标识符.使事情有效的关键是维护一个描述这些表如何相关的表.我叫这个表加入.现在我可以像这样创建一个动态过程:

CREATE PROC pDynamicFind
  (
    @Tables varchar(256)
  , @Joins VARCHAR(256)
  , @Predicate VARCHAR(256)
  )
AS
BEGIN
  SET NOCOUNT ON;

    DECLARE @SQL NVARCHAR(MAX) = 
'With x as 
    (
    SELECT
    a.Id
  , {nameColumns}
  From {joins}
  Where {predicate}
  )
SELECT *
From x
  UNPIVOT (Value FOR TableName In ({nameColumns})) AS unpt
'
    DECLARE @Tbls TABLE (id INT IDENTITY, tableName VARCHAR(256), joinType VARCHAR(16))
    DECLARE @Start INT = 2
    DECLARE @alphas VARCHAR(26) = 'abcdefghijklmnopqrstuvwxyz'

    --Comma seperated into temp table (realistically most people create a function to do this so you don't have to do it over and over again)
    WHILE LEN(@Tables) > 0
    BEGIN
        IF PATINDEX('%,%', @Tables) > 0
        BEGIN
            INSERT INTO @Tbls (tableName) VALUES (RTRIM(LTRIM(SUBSTRING(@Tables, 0, PATINDEX('%,%', @Tables)))))
            SET @Tables = SUBSTRING(@Tables, LEN(SUBSTRING(@Tables, 0, PATINDEX('%,%', @Tables)) + ',') + 1, LEN(@Tables))
        END
        ELSE
        BEGIN
            INSERT INTO @Tbls (tableName) VALUES (RTRIM(LTRIM(@Tables)))
            SET @Tables = NULL
        END
    END

    --Have to iterate over this one seperately
    WHILE LEN(@Joins) > 0
    BEGIN
        IF PATINDEX('%,%', @Joins) > 0
        BEGIN
            Update @Tbls SET joinType = (RTRIM(LTRIM(SUBSTRING(@Joins, 0, PATINDEX('%,%', @Joins))))) WHERE id = @Start
            SET @Joins = SUBSTRING(@Joins, LEN(SUBSTRING(@Joins, 0, PATINDEX('%,%', @Joins)) + ',') + 1, LEN(@Joins))
            SET @Start = @Start + 1
        END
        ELSE
        BEGIN
            Update @Tbls SET joinType = (RTRIM(LTRIM(@Joins))) WHERE id = @Start
            SET @Joins = NULL
            SET @Start = @Start + 1
        END
    END

    DECLARE @Join VARCHAR(256) = ''
    DECLARE @Cols VARCHAR(256) = ''

    --Determine dynamic columns and joins
    Select 
      @Join += CASE WHEN joinType IS NULL THEN t.tableName + ' ' + SUBSTRING(@alphas, t.id, 1) 
      ELSE ' ' + joinType + ' JOIN ' + t.tableName + ' ' + SUBSTRING(@alphas, t.id, 1) + ' ON ' + SUBSTRING(@alphas, t.id-1, 1) + '.' + REPLACE(j.JoinClause, '= ', '= ' + SUBSTRING(@alphas, t.id, 1) + '.' )
      END
    , @Cols += CASE WHEN joinType IS NULL THEN t.tableName + 'Name' ELSE ' , ' + t.tableName + 'Name' END
    From @Tbls t
      LEFT JOIN Joins j ON t.tableName = j.DestinationTable

    SET @SQL = REPLACE(@SQL, '{joins}', @Join)
    SET @SQL = REPLACE(@SQL, '{nameColumns}', @Cols)
    SET @SQL = REPLACE(@SQL, '{predicate}', @Predicate)

    --PRINT @SQL
    EXEC sp_executesql @SQL
END
GO
Run Code Online (Sandbox Code Playgroud)

我现在有一个用于查找事物的介质,使其成为存根查询,可以说我可以替换from语句的来源,我查询的内容,我用来查询的值.我会得到这样的结果:

EXEC pDynamicFind 'Customer, Product', 'Inner', 'CustomerName = ''Acme'''
EXEC pDynamicFind 'Customer, Product, Vehicle', 'Inner, Inner', 'VehicleName = ''Car'''
Run Code Online (Sandbox Code Playgroud)

那么在EF中设置并在代码中使用它呢?那么你可以添加到EF的过程并从中获取数据作为上下文.这解决的答案是,我现在基本上回馈了一个固定的对象,尽管我可能添加了很多列.如果我的模式总是将'(表)名称'表示为N个表,我可以通过取消标记来规范化我的结果,然后只为我拥有的多个表获取N个行.因此,当您获得更大的结果集时,性能可能会更差,但只要使用类似的结构,就有可能进行许多连接.

我要说的是,SQL最终会获得你的数据并且做出疯狂的连接,而Linq的结果有时会超出它的价值.但是如果你有一个小的结果集和一个小的数据库,你可能没问题.这只是一个示例,说明如何使用动态SQL在SQL中获得完全不同的对象,以及在编写proc代码后它能以多快的速度执行某些操作.这只是一种皮肤猫的方法,我确信它有很多.问题是,无论你采用动态连接的方式,或者解决问题的方法都需要某种类型的规范化标准,工厂模式或其他地方,它说我可以有N个输入,无论什么都会产生相同的X对象.我通过垂直结果集执行此操作,但如果您想要一个与"name"不同的列,那么您将不得不为此编写更多代码.然而,如果你想要描述但我想建立一个日期字段的谓词的方式我这样就可以了.