web-dev-qa-db-fra.com

Erreur: "L'expression LINQ spécifiée contient des références à des requêtes associées à différents contextes"

Je reçois le message d'erreur indiqué dans le titre d'une requête LINQ comprenant deux tables provenant de deux fichiers edmx différents. Voici la requête:

var query = (from a in db1.Table1
           join b in db1.Table2 on a.Id equals b.Id
           orderby a.Status
           where b.Id == 1 && a.Status == "new"
           select new
           {
               Id = a.Id,
               CompanyId = (from c in db2.Company
                            where s.Id == a.Id
                            select
                            new { c.CompanyId })
           });

db1 et db2 sont des contextes associés à deux fichiers edmx différents. Comment puis-je surmonter cette erreur?

55
Ashiq A N

Vous devrez effectuer deux requêtes sur la base de données:

var IDs =  (from a in db1.Table1 
            join b in db1.Table2 on a.Id equals b.Id 
            orderby a.Status 
            where b.Id == 1 && a.Status == "new" 
            select new a.Id).ToArray();

var query = from c in db2.Company
            join a in IDs on c.Id equals a.Id
            select new { Id = a.Id, CompanyId = c.CompanyId };

Le .ToArray() est crucial. Cela empêche EF d'essayer d'exécuter la requête combinée (ce qui échouera car il utilise deux contextes différents). Vous pouvez utiliser .AsEnumerable() si vous préférez garder le chargement paresseux.


Et votre question de suivi:

Existe-t-il un autre moyen d'optimiser la requête LINQ? C'est, effectuer l'action dans une seule requête LINQ elle-même?

Pour que votre requête d'origine puisse être exécutée avec succès, elle ne doit utiliser qu'un seul contexte de données, ce qui signifie que toutes les données doivent être disponibles à partir d'un seul EDMX, ce qui signifie une seule chaîne de connexion. Vous pouvez y parvenir de plusieurs manières:

  • Si les deux tables sont sur la même base de données, ajoutez-les à un seul EDMX.
  • S'ils se trouvent sur des bases de données différentes mais sur la même instance, créez une vue sur l'une des bases de données sélectionnées dans la table de l'autre base de données, puis ajoutez la table locale et la vue à un seul EDMX.
  • S'ils se trouvent sur différentes instances/serveurs, créez un serveur lié, puis créez une vue de la table sur le serveur lié, puis ajoutez la table locale et la vue à un seul EDMX.
104
Allon Guralnek

Vous devez soit ajouter la deuxième table au modèle du premier contexte. S'il s'agit de plusieurs bases de données, vous devez effectuer la recherche secondaire côté client à l'aide d'une jointure Linq to Objects.

2
Jim Wooley

Vous devez créer manuellement EntityConnection, qui contient des ressources provenant de tous les .EDMX que vous souhaitez utiliser.

méthode a) 

<add name="MyConnection"
connectionString="metadata=res://*/Entities.ModuleA.csdl|res://*/Entities.ModuleA.ssdl|res://*/Entities.ModuleA.msl|res://*/Entities.ModuleB.csdl|res://*/Entities.ModuleB.ssdl|res://*/Entities.ModuleB.msl;
provider=System.Data.SqlClient;provider connection string=&quot;MyConnectionString&quot;"
providerName="System.Data.EntityClient" />

using (EntityConnection oEntityConnection =
    new EntityConnection("name=MyConnection"))
{
    using(DbContext oDBContext = new DbContext(oEntityConnection))
    {
        //your code - available are entities declared in Entities.ModuleA and Entities.ModuleB
    }
}

méthode b)

 using (EntityConnection oEntityConnection =
        new EntityConnection(new MetadataWorkspace(
        new string [] { 
"res://Entities.ModuleA/", 
"res://Entities.ModuleB/" 
},
        new Assembly[] { 
Assembly.GetAssembly(typeof(Entities.ModuleA.AnyType)),
Assembly.GetAssembly(typeof(Entities.ModuleB.AnyType)) 
}
        )))
    {
        using(DbContext oDBContext = new DbContext(oEntityConnection))
        {
            //your code - available are entities declared in Entities.ModuleA and Entities.ModuleB
        }
    }
0
Kosma Bieńkowski