我正在使用Entity Framework(4.2,如果这很重要),我有一个具有复合主键的模型(两个int列)。我有一对整数的列表,它们代表了我想从数据库中提取的对象列表。有没有一种简单的方法可以使用单个查询来提取所有这些对象?
我已尝试将查询加入我的列表,如下所示:
List<Tuple<int, int>> ids = GetIds();
var data =
from e in ctx.CompositeEntities
join i in ids on new {e.KeyA, e.KeyB} equals new {KeyA = i.Item1, KeyB = i.Item2}
select e;
然而,这总是会导致异常“无法创建类型'System.Tuple`2'的常量值。在此上下文中仅支持基本类型(例如Int32,String和Guid')。” p>
答案 0 :(得分:5)
我希望看到一种更清洁的方法,但是......至少它应该有效。
<强>解决方法1 强>
您需要什么:连接您的元组列表,然后使用SqlFunctions.StringConvert连接您实体的“int keys”。因为它只需要double或decimal作为参数,所以你必须首先将int转换为double。
List<Tuple<int, int>> ids = GetIds();
var concatenatedIds = ids.Select(m => m.Item1 + "," + m.Item2).ToList();
var result = ctx.CompositeEntities
.Where(conatenatedIds.Contains(
SqlFunctions.StringConvert((double)m.KeyA) +
"," +
SqlFunctions.StringConvert((double)m.KeyB)));
<强>溶液2 强>
List<Tuple<int, int>> ids = GetIds();
var predicate = Predicate.False<CompositeEntity>();
foreach (var tuple in ids)
predicate = predicate.Or(m => m.KeyA == tuple.Item1 && m.KeyB == tuple.Item2);
var result = ctx.CompositeEntities.Where(predicate);
解决方案3
先列举,然后进行比较。 当然,这将从数据库中获取所有CompositeEntities。
答案 1 :(得分:0)
我无法尝试这一点,但尝试使用类似于where where的内容。
from e in ctx.CompositeEntities
where ids.Where(i => e.KeyA == i.Item1 && e.KeyB == i.Item2).Count() > 0
select e;
=====编辑=====
好吧,它失败了同样的例外,谢谢你的鼓励。假设你的密钥是int而不是bigint
,以下内容如何public class e1 {
public int KeyA { get; set; }
public int KeyB { get; set; }
}
public class e1Configuration : EntityTypeConfiguration<e1> {
public e1Configuration()
: base() {
HasKey(x => new { x.KeyA, x.KeyB });
}
}
public class TestEFContext : DbContext {
public IDbSet<e1> es { 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 e1Configuration());
}
}
class Program {
static void Main(String[] args) {
using (TestEFContext c = new TestEFContext(@"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True")) {
c.es.Add(new e1 { KeyA = 1, KeyB = 1 });
c.es.Add(new e1 { KeyA = 1, KeyB = 2 });
c.es.Add(new e1 { KeyA = Int32.MaxValue, KeyB = 2 });
c.SaveChanges();
}
List<Tuple<int, int>> ids = new List<Tuple<int, int>> {
new Tuple<int, int>(1, 1),
new Tuple<int, int>(Int32.MaxValue, 2),};
List<Int64> lis = (from t in ids select (Int64)t.Item1 * 2^ 32 + t.Item2).ToList();
using (TestEFContext c0 = new TestEFContext(@"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True")) {
var v = from e in c0.es
where lis.Contains((Int64)e.KeyA * 2 ^ 32 + e.KeyB)
select e;
Console.WriteLine(v.Count());
}
}
}
答案 2 :(得分:0)
我正在使用几乎相同的方案,但我会尝试将其映射到上面的那个 - 所以如果它不能编译就告诉我。
这与Raphaël的例子2基本相同,但我无法运行。我正在构建谓词作为单个实体的查询联合,每个元组一个。
List<Tuple<int, int>> ids = GetIds();
ids.Aggregate<Tuple<int,int>,IQueryable<CompositeEntity>>(
null,
(current, id) =>
current == null ? SingleCompositeEntity(ctx.CompositeEntities, id)
: current.Union(SingleCompositeEntity(ctx.CompositeEntities, id)));
}
private static IQueryable<CompositeEntity>
SingleCompositeEntity(IQueryable source, Tuple<int,int> tuple)
{
return source.Where(m => m.KeyA == tuple.Item1 && m.KeyB == tuple.Item2)
}
答案 3 :(得分:-1)
未经测试,但我认为会有效。
向实体对象添加属性以将键公开为元组。
public Tuple<int, int> TupleKey
{
get { return new Tuple<int, int>(_keyA, _keyB);}
}
然后更改您的查询以使用此新属性。
List<Tuple<int, int>> ids = GetIds();
var data = from e in ctx.CompositeEntities
where ids.Contains(e.TupleKey)
select e;