4

我正在使用实体框架(如果重要,则为 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')。”

4

4 回答 4

6

我希望看到一种更清洁的方法来做到这一点,但是......至少它应该可以工作。

解决方案1

您需要什么:连接您的元组列表,然后使用SqlFunctions.StringConvert从您的实体连接“int 键” 。因为它只需要 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

使用PredicateBuilder

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。

于 2013-01-30T16:03:26.597 回答
0

我无法尝试这个,但尝试使用类似 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());
        }

    }
}
于 2013-01-30T15:42:46.720 回答
0

我正在处理一个几乎相同的场景,但我会尝试将它映射到上面的场景 - 如果它不能编译,请告诉我。

这与 Raphaël 的示例 2 的基本思想相同,但我无法让它运行。我将 Predicate 构建为单个实体的查询联合,每个元组一个。

  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)

}
于 2014-04-15T15:14:19.923 回答
-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;
于 2013-01-30T16:14:27.843 回答