我有一张桌子,让我们说tblCar包含所有相关栏目,如Id,Make,Model,Color等。
我有一个包含两个参数Id和Model的汽车搜索模型。
public class CarSearch
{
public int Id { get; set; }
public string Model { get; set; }
}
var carSearchObjets = new List<CarSearch>();
使用原始数据列表(如Id列表),可以获得那些我可以做的ID:
var idList = new List<int> { 1, 2, 3 };
var carsFromQuery = context.Cars.Where(x => idList.Contains(x.Id);
但是如果我必须从列表中获取所有带有Id和型号的汽车,我该怎么做?在内存对象和表之间无法进行简单连接。
我需要类似的东西,
from m in context.Cars
join n in carSearchObjets
on new { Id = n.Id, Model = n.Model } equals new { Id = m.Id, Model = m.Model }
select m;
这显然不起作用。
请忽略任何拼写错误。如果您需要更多信息或问题不明确,请与我们联系。
答案 0 :(得分:1)
管理它的一种(丑陋但工作)的方法是使用串联与“从未使用过”的concat char。
我的意思是一个永远不会出现在数据中的字符。这总是危险的,因为......永远不会确定,但你已经有了这个想法。
例如,我们会说我们的“从未使用过”的concat char将是~
这对于perf来说并不好,但至少在工作:
var carSearchObjectsConcatenated = carSearchObjets.Select(m => new { m.Id + "~" + m.Model});
然后你可以再次使用Contains
(在数据库上连接):如果你想连接数据库端的字符串和数字,你需要使用SqlFunctions.StringConvert
。
var result = context.Cars.Where(m =>
carSearchObjectsConcatenated.Contains(SqlFunctions.StringConvert((double)m.Id) + "~" + m.Model);
修改强>
另一个解决方案是使用Sorax提到的PredicateBuilder,或者如果你不想要第三方lib(或者PredicateBuilder非常好),可以构建你自己的Filter方法。
静态类中的那样:
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);
}
使用
var result = context.Cars.FilterCars(carSearchObjets);
这将生成一个类似
的sqlselect ...
from Car
where
(Id = 1 And Model = "ax") or
(Id = 2 And Model = "az") or
(Id = 3 And Model = "ft")
答案 1 :(得分:1)
'PredicateBuilder'可能会有所帮助。
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);
请注意有关EF的链接中的文字:
如果您正在使用Entity Framework,则需要完整的LINQKit - 用于AsExpandable功能。你可以参考 LINQKit.dll或将LINQKit的源代码复制到您的应用程序中。
答案 2 :(得分:0)
老派解决方案..
//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);
}
不要担心for循环。
答案 3 :(得分:0)
我登陆了传递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())));
我为实体框架核心用户创建了一个nuget包扩展名: