C# 使用对象列表联接表

C# 使用对象列表联接表,c#,entity-framework,join,linq-to-entities,C#,Entity Framework,Join,Linq To Entities,我有一个表,比如tblCar,它包含所有相关列,如Id、Make、Model、Color等 我有一个包含两个参数Id和模型的汽车搜索模型 public class CarSearch { public int Id { get; set; } public string Model { get; set; } } var carSearchObjets = new List<CarSearch>(); 这显然行不通 请忽略任何打字错误。如果您需要更多信息或问题不清楚,

我有一个表,比如tblCar,它包含所有相关列,如Id、Make、Model、Color等

我有一个包含两个参数Id和模型的汽车搜索模型

public class CarSearch
{
   public int Id { get; set; }
   public string Model { get; set; }
}

var carSearchObjets = new List<CarSearch>();
这显然行不通

请忽略任何打字错误。如果您需要更多信息或问题不清楚,请告诉我

一种(丑陋但有效)的管理方法是使用“从未使用过”concat字符的连接

我指的是一个永远不会出现在数据中的字符。这总是很危险的,因为。。。永远都不确定,但你已经有了主意

例如,我们会说我们的“从未使用过”concat字符将是
~

这不利于性能,但至少可以工作:

var carSearchObjectsConcatenated = carSearchObjets.Select(m => new { m.Id + "~" + m.Model});
然后,您可以再次使用
Contains
(也在db上连接):如果您想连接db端的字符串和数字,则需要使用
SqlFunctions.StringConvert

var result = context.Cars.Where(m => 
                carSearchObjectsConcatenated.Contains(SqlFunctions.StringConvert((double)m.Id) + "~" + m.Model);
编辑

另一个解决方案是使用PredicateBuilder,正如Sorax所提到的,或者如果您不需要第三方库(但是PredicateBuilder非常好),则构建您自己的筛选方法

在静态类中类似的情况:

public static IQueryable<Car> FilterCars(this IQueryable<Car> cars, IEnumerable<SearchCar> searchCars)
        {
            var parameter = Expression.Parameter(typeof (Car), "m");

            var idExpression = Expression.Property(parameter, "Id");
            var modelExpression = Expression.Property(parameter, "Model");

            Expression body = null;
            foreach (var search in searchCars)
            {
                var idConstant = Expression.Constant(search.Id);
                var modelConstant = Expression.Constant(search.Model);

                Expression innerExpression = Expression.AndAlso(Expression.Equal(idExpression, idConstant), Expression.Equal(modelExpression, modelConstant));
                body = body == null
                    ? innerExpression
                    : Expression.OrElse(body, innerExpression);
            }
            var lambda = Expression.Lambda<Func<Car, bool>>(body, new[] {parameter});
            return cars.Where(lambda);
        }
这将生成如下所示的sql

select ...
from Car
where 
 (Id = 1 And Model = "ax") or
 (Id = 2 And Model = "az") or
 (Id = 3 And Model = "ft")
可能会有帮助

var predicate = PredicateBuilder.False<Car>();
carSearchObjects
.ForEach(a => predicate = predicate.Or(p => p.Id == a.Id && p.Model == a.Model));

var carsFromQuery = context.Cars.AsExpandable().Where(predicate);
var predicate=PredicateBuilder.False();
汽车搜索对象
.ForEach(a=>predicate=predicate.Or(p=>p.Id==a.Id&&p.Model==a.Model));
var carsFromQuery=context.Cars.AsExpandable().Where(谓词);
请注意链接中有关EF的文字:

如果您使用的是实体框架,则需要完整的LINQKit- 对于可扩展的功能。你可以选择 或将LINQKit的源代码复制到应用程序中

老派的解决办法

//in case you have a 
List<CarSearch> search_list; //already filled

List<Cars> cars_found = new List<Cars>();
foreach(CarSearch carSearch in search_list)
{
    List<Cars> carsFromQuery = context.Cars.Where(x => x.Id == carSearch.Id && x.Model == carSearch.Model).ToList();
    cars_found.AddRange(carsFromQuery);
}
//如果您有
列表搜索列表//已满
列出找到的车辆=新列表();
foreach(搜索列表中的搜索)
{
列出carsFromQuery=context.Cars.Where(x=>x.Id==carSearch.Id&&x.Model==carSearch.Model).ToList();
cars\u found.AddRange(carsFromQuery);
}

Abd不要担心for循环。

我将一个xml列表作为参数传递给sql查询,并加入到该查询中:

var xml = new XElement("Cars", yourlist.Select(i => new XElement("Car", new XElement("Id", i.Id), new XElement("Model", i.Model))));
var results = Cars
        .FromSql("SELECT cars.*"
                + "FROM @xml.nodes('/Cars/Car') Nodes(Node)"
                + "JOIN Cars cars on cars.Id = Nodes.Node.value('Id[1]', 'int') and cars.Model = Nodes.Node.value('Model[1]', 'varchar(100)')",
            new SqlParameter("@xml", new SqlXml(xml.CreateReader())));
对于entity framework核心用户,我创建了一个nuget包扩展:


与简单联接相比,所有转换是否会显著降低查询性能?好吧,您不能将联接用于对象和db实体。性能降低的原因是(如果我没有错的话)生成的sql不会使用带有串联数据的索引。真的,不要担心循环?在这种情况下(db查询),每个循环都是一个db调用。所以这可能是个问题。。。(当然,这取决于搜索列表的大小)。顺便说一句,你可以使用
cars\u found.AddRange(carsFromQuery)
,但这是一个细节。我估计汽车搜索列表不会太大。无论如何,问题中没有提到时间问题。无论如何,我不认为这会是一个世界末日的问题。谢谢你提供的详细信息,我编辑了我的答案。
var predicate = PredicateBuilder.False<Car>();
carSearchObjects
.ForEach(a => predicate = predicate.Or(p => p.Id == a.Id && p.Model == a.Model));

var carsFromQuery = context.Cars.AsExpandable().Where(predicate);
//in case you have a 
List<CarSearch> search_list; //already filled

List<Cars> cars_found = new List<Cars>();
foreach(CarSearch carSearch in search_list)
{
    List<Cars> carsFromQuery = context.Cars.Where(x => x.Id == carSearch.Id && x.Model == carSearch.Model).ToList();
    cars_found.AddRange(carsFromQuery);
}
var xml = new XElement("Cars", yourlist.Select(i => new XElement("Car", new XElement("Id", i.Id), new XElement("Model", i.Model))));
var results = Cars
        .FromSql("SELECT cars.*"
                + "FROM @xml.nodes('/Cars/Car') Nodes(Node)"
                + "JOIN Cars cars on cars.Id = Nodes.Node.value('Id[1]', 'int') and cars.Model = Nodes.Node.value('Model[1]', 'varchar(100)')",
            new SqlParameter("@xml", new SqlXml(xml.CreateReader())));