我有一组像这样创建的匿名对象:
var srcCategories = srcSet.Categories.Select(c => new
{
ApplicationId = c.IsGLobal ? (long?)null : c.App.Id,
c.Name
});
请注意,此集合 not 来自我的数据上下文;它是从外部系统的输入生成的。我需要将两个 ApplicationId
和Name
映射到我的数据库中的实体。到目前为止,这是我成功实现它的唯一方法:
var trgCategoryIds =
(from c in core.Domain.Categories.AsEnumerable()
let ci = new { c.ApplicationId, c.Name }
where srcCategories.Contains(ci)
select c.Id)
.ToArray();
但这要求我先将整个Categories
表拉入内存。我正在寻找一种更有效的方法,最好是在一个查询中。我已经尝试了以下所有选项,它们都不能转换为sql:
// Removed .AsEnumerable()
var trgCategoryIds =
(from c in core.Domain.Categories
let ci = new { c.ApplicationId, c.Name }
where srcCategories.Contains(ci)
select c.Id)
.ToArray();
// Use .Any() instead of .Contains()
var trgCategoryIds =
(from c in core.Domain.Categories
where srcCategories.Any(s => s.ApplicationId == c.ApplicationId && s.Name == s.Name)
select c.Id)
.ToArray();
// Use Tuples instead of anon types
var srcCategories = srcSet.Categories.Select(c => Tuple.Create(...));
var trgCategoryIds =
(from c in core.Domain.Categories
let ci = Tuple.Create(c.ApplicationId, c.Name)
where srcCategories.Contains(ci)
select c.Id)
.ToArray();
答案 0 :(得分:2)
你想做的事情真的不可能,因为首先没有简单的SQL。实际上,你想要:
select * from Catagories where (ApplicationID = 1 and Name = "Foo")
or (ApplicationID = 2 and Name = "Bar")
or (ApplicationID = 2345 and Name = "Fizbuzz")
or ...
实体框架,据我所知,无法自动创建该类型的查询。它可以通过将Contains()
转换为IN (...)
来处理单个测试,但是当您不能IN
时,没有简单的SQL用于join
。但是,您可以使用Predicate Builder库来构造此类OR
查询。页面上的第二个示例应该就是您所需要的。
适合您的使用:
var predicate = PredicateBuilder.False<Category>();
foreach (var cat in srcCategories)
{
var temp = cat;
predicate = predicate.Or (p => p.ApplicationId == temp.ApplicationId && p.Name == temp.Name);
}
return core.Domain.Categories.AsExpandable().Where (predicate);
}
答案 1 :(得分:1)
如果两个Categories
集合来自不同的数据库上下文,那么就无法将其中一个集合到内存中。
如果他们共享数据库上下文,那么您要做的就是简单地加入两个表:
var query =
from domainCat in srcCategories
join sourceCat in srcSet.Categories
on new { domainCat.ApplicationId, domainCat.Name } equals
new { sourceCat.ApplicationId, sourceCat.Name }
select sourceCat.Id;
答案 2 :(得分:0)
如何调整以下代码,将ks作为格式化类别(Id +“ - ”+ Name)。
using System;
using System.Linq;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data.Entity.ModelConfiguration;
using System.Data.Objects.SqlClient;
namespace testef {
//Model
public class CObj {
public CObj() {
}
public Int32 Id { get; set; }
public String SomeCol { get; set; }
}
//Configuration for CObj
public class CObjConfiguration : EntityTypeConfiguration<CObj> {
public CObjConfiguration() {
HasKey(x => x.Id);
}
}
public class TestEFContext : DbContext {
public IDbSet<CObj> objects { get; set; }
public TestEFContext(String cs)
: base(cs) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new CObjConfiguration());
}
}
class Program {
static void Main(String[] args) {
String cs = @"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext c = new TestEFContext(cs)) {
c.objects.Add(new CObj { Id = 1, SomeCol = "c"});
c.SaveChanges();
}
IEnumerable<String> ks = new List<String> { String.Format("{0,10}-c", 1) };
foreach (var k in ks) {
Console.WriteLine(k);
}
using (TestEFContext c = new TestEFContext(cs)) {
var vs = from o in c.objects
where ks.Contains(SqlFunctions.StringConvert((Decimal?)o.Id, 10) + "-" + o.SomeCol)
select o;
foreach (var v in vs) {
Console.WriteLine(v.Id);
}
}
}
}
}
答案 3 :(得分:-1)
var trgCategoryIds =
(from c in core.Domain.Categories.AsEnumerable()
where sourceCategories.Any(sc=> sc.ApplicationId == c.ApplicationId
&& sc.Name == c.Name)
select c.Id)
.ToArray();