Как обойти «Внутреннюю ошибку поставщика данных .NET Framework 1025.»? - PullRequest
5 голосов
/ 01 марта 2012

Сначала я использую Entity Framework 4.3, POCO, базу данных и получаю следующую ошибку:

Внутренняя ошибка поставщика данных .NET Framework 1025.

ВОПРОС: Я думаю, что мой запрос выражает мое намерение, но мне кажется, что я попал в эту ошибку, поэтому мне интересно, знает ли кто-нибудь, как я мог бы структурировать свой запрос по-другому, чтобы обойти эту ошибку?

Вот сценарий ...

У меня есть база данных SQL Server 2008 с двумя таблицами - A и B:

A

  • AId (int - не null - идентификатор - первичный ключ)
  • AName (nvarchar (10) - не ноль)

B

  • BId (int - не null - идентификатор - первичный ключ)
  • SomeName (nvarchar (10) - не ноль)
  • AId (int - не ноль - внешний ключ, подключающийся к AId в таблице A)

Затем я определяю контекст следующим образом:

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" находится в списке предоставленных имен, поэтому я делаю это:

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 (так, чтобы при подсчете колла выше было 3).

Ответы [ 3 ]

8 голосов
/ 01 марта 2012

Причина, по которой это происходит, неуловима.

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)));
2 голосов
/ 01 марта 2012

Я разработал решение для этого, на случай, если кому-то будет интересно.Выполнение следующего является эквивалентным и не приводит к исключению в вопросе:

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

Я не знаю, является ли это лучшим способом, хотя!?

1 голос
/ 01 марта 2012

Семантика вашего запроса выглядит хорошо для меня; очевидно, что получение внутренней ошибки провайдера не является предполагаемым поведением! Я ожидал бы более явного сообщения о том, что 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 таким образом, чтобы при пересечении имен B s с фиксированным списком были получены все B s)

хотя я не пробовал это, чтобы увидеть, может ли 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 s 'сводился к нулю, вынимая фиксированный список)

также не опробован.

...