有以下示例:
var myIds = db.Table1.Where(x=>x.Prop2 == myFilter).Select(x=>x.Id).ToList();
var results = db.Table2.Where(x=> myIds.Contains(x.T1)).ToList();
这部分很简单。
但是,现在我面临一个“轻微”更改,其中我的“过滤器列表”具有2个属性,而不仅仅是一个:
// NOTE: for stackoverflow simplification I use a basic query to
// get my "myCombinationObject".
// In reality this is a much more complex case,
// but the end result is a LIST of objects with two properties.
var myCombinationObject = db.Table3.Where(x=>x.Prop3 == myFilter)
.Select(x=> new {
Id1 = x.T1,
Id2 = x.T2
}).ToList();
var myCombinationObjectId1s = myCombinationObject.Select(x=>xId1).ToList();
var myCombinationObjectId2s = myCombinationObject.Select(x=>xId2).ToList();
// step#1 - DB SQL part
var resultsRaw = db.Tables.Where( x=>
myCombinationObjectId1s.Contains(x.Prop1)
|| myCombinationObjectId2s.Contains(x.Prop2))
.ToList();
// step#2 - Now in memory side - where I make the final combination filter.
var resultsFiltered = resultsRaw.Where( x=>
myCombinationObject.Contains(
new {Id1 = x.Prop1, Id2 = x.Prop2 }
).ToList();
我的问题:是否有可能在步骤1中合并步骤2(在linq中查询实体)?
我曾经设法做过您想做的事,但是这很困难,需要稍微更改实体模型。您需要一个实体来映射类型
new {Id1 = x.Prop1, Id2 = x.Prop2 }
因此,您需要具有2个属性的实体-Id1和Id2。如果您有一个-很好,如果没有,则将这样的实体添加到模型中:
public class CombinationObjectTable
{
public virtual Guid Id1 { get; set; }
public virtual Guid Id2 { get; set; }
}
将其添加到模型中:
public DbSet<CombinationObjectTable> CombinationObjectTable { get; set; }
创建新的迁移并将其应用到数据库(数据库现在将具有附加表CombinationObjectTable)。之后,您开始构建查询:
DbSet<CombinationObjectTable> combinationObjectTable = context.Set<CombinationObjectTable>();
StringBuilder wholeQuery = new StringBuilder("DELETE * FROM CombinationObjectTable");
foreach(var obj in myCombinationObject)
{
wholeQuery.Append(string.Format("INSERT INTO CombinationObjectTable(Id1, Id2) VALUES('{0}', '{1}')", obj.Id1, obj.Id2);
}
wholeQuery.Append(
db.Tables
.Where( x=>
myCombinationObjectId1s.Contains(x.Prop1)
|| myCombinationObjectId2s.Contains(x.Prop2))
.Where( x=>
combinationObjectTable.Any(ct => ct.Id1 == x.Id1 && ct.Id2 == x.Id2)
).ToString();
);
var filteredResults = context.Tables.ExecuteQuery(wholeQuery.ToString());
由于这个原因,您的主要查询保持用linq编写。如果您不想将新表添加到数据库中,这也是可以实现的。向模型添加新的类CombinationObjectTable,生成新的迁移以进行添加,然后从迁移代码中删除创建该表的代码。之后,进行迁移。这样,数据库架构不会更改,但EF会认为数据库中存在CombinationObjectTable。代替它,您将需要创建一个临时表来保存数据:
StringBuilder wholeQuery = new StringBuilder("CREATE TABLE #TempCombinationObjectTable(Id1 uniqueidentifies, Id2 uniqueidentifier);");
当您在linq查询上调用ToString方法时,将CombinationObjectTable更改为#TempCombinationObjectTable:
...
.ToString()
.Replace("CombinationObjectTable", "#TempCombinationObjectTable")
值得考虑的其他事情是使用查询参数在INSERT语句中传递值,而不是仅将它们自己包含在查询中-这当然也可以通过EF实现。该解决方案尚未完全准备好应用,而是在暗示您可能朝哪个方向发展该解决方案。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句