如何通过复合键检索多个实体?

时间:2013-01-30 15:30:44

标签: sql-server entity-framework entity-framework-4 composite-key

我正在使用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>

4 个答案:

答案 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

使用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。

答案 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;