5

我首先使用实体​​框架 4.3、POCO、数据库,我收到以下错误:

内部 .NET Framework 数据提供程序错误 1025。

问题: 我认为我的查询表达了我的意图,但我似乎遇到了这个错误,所以我想知道是否有人知道我可以如何以不同的方式构建我的查询来解决这个错误?

这是场景...

我有一个 SQL Server 2008 数据库,它有 2 个表 - A 和 B:

一种

  • AId(int - 非空 - 标识 - 主键)
  • AName (nvarchar(10) - 不为空)

  • BId(int - 非空 - 身份 - 主键)
  • SomeName (nvarchar(10) - 不为空)
  • AId(int - 非空 - 连接到表 A 中的 AId 的外键)

然后我像这样定义上下文:

public class DatabaseContext : DbContext
{
    public DatabaseContext(string name)
        : base(name)
    {
        Configuration.AutoDetectChangesEnabled = false;
        As = Set<A>();
        Bs = Set<B>();
    }

    public DbSet<A> As { get; private set; }
    public DbSet<B> Bs { get; private set; }
}

实体类是这样的:

public class A
{
    public int AId { get; set; }
    public string AName { get; set; }
    public virtual ICollection<B> Bs { get; private set; }

    public void AddB(B b)
    {
        if (b == null)
        {
            throw new ArgumentNullException("b");
        }

        if (Bs == null)
        {
            Bs = new List<B>();
        }

        if (!Bs.Contains(b))
        {
            Bs.Add(b);
        }

        b.A = this;
    }
}

public class B
{
    public int BId { get; set; }
    public A A { get; set; }
    public string SomeName { get; set; }
}

现在查询...

我想要的是每个“B SomeName”都在提供的名称列表中的所有 As,所以我这样做:

var names = new[] {"Name1", "Name2"};

var ctx = new DatabaseContext("EFPlayingEntities");
var res = ctx.As.Where(a => a.Bs.Select(b => b.SomeName).All(names.Contains));

// Here I evaluate the query and I get:
//   Internal .NET Framework Data Provider error 1025.
Console.WriteLine(res.Count());

为了清楚我的意思,如果表数据如下所示:

AId,AName
1,A1
2,A2
3,A3
4,A4

BId,SomeName,AId
1,Name1,1
2,Name2,1
3,Name1,2
4,Name1,3
5,Name3,3
6,Name1,4
7,Name2,4

我希望返回 A1、A2 和 A4(因此上面的 count 调用将返回 3)。

4

3 回答 3

9

发生这种情况的原因很微妙。

Queryable.All需要用Expression. 仅传入方法 'reference' 会创建一个委托,然后Enumerable.All成为候选者而不是预期的Queryable.All.

这就是为什么您作为答案发布的解决方案可以正常工作的原因。

编辑

因此,如果您这样编写语句,它将毫无例外地工作:

var res = ctx.As.Where(
  a => a.Bs.Select(b => b.SomeName).All(b => names.Contains(b)));
于 2012-03-01T14:30:39.090 回答
2

我已经制定了一个解决方案,以防万一有人感兴趣。执行以下操作是等效的,并且不会导致问题中的异常:

var res = ctx
    .Bs
    .GroupBy(b => b.A)
    .Where(g => g.All(b => names.Contains(b.SomeName)))
    .Select(g => g.Key);

我不知道这是否是最好的方法!?

于 2012-03-01T13:12:46.600 回答
1

您查询的语义对我来说看起来不错;显然,获得内部提供程序错误不是预期的行为!如果这实际上是问题所在,我会期待一些关于 EF 无法将您的查询转换为存储操作的更明确的消息。

做你想做的另一种方法是:

var names = new[] {"Name1", "Name2"};
var nameCount = names.Length;

var ctx = new DatabaseContext("EFPlayingEntities");
var result = ctx.As
    .Where(a => a.Bs
                 .Select(b => b.SomeName)
                 .Intersect(names)
                 .Count() == a.Bs.Count());

(得到每一个A这样的,将其Bs 的名称与固定列表相交给出所有的Bs)

虽然我还没有尝试过这个来看看 EF 是否可以成功翻译。

其他方式:

var names = new[] {"Name1", "Name2"};

var ctx = new DatabaseContext("EFPlayingEntities");
var result = ctx.As
    .Where(a => !a.Bs.Select(b => b.SomeName).Except(names).Any());

(通过取出固定列表来获取每一个A这样的名称列表)B

也未试过。

于 2012-03-01T13:23:06.640 回答