En essayant de résoudre:Tables temporaires dans Linq - Quelqu'un a vu un problème avec ça?
Linq .Contains with large set causes TDS error
Je pense que je suis tombé sur une solution, et je voudrais voir si elle est une façon cachère d'aborder le problème.
(résumé court) Je souhaiterais linq-joiner contre une liste d'identifiants d'enregistrement qui ne sont pas (entièrement ou au moins facilement) générés en SQL. C'est une grande liste qui dépasse souvent la limite de 2100 éléments pour l'appel TDS RPC. Donc, ce que j'aurais fait dans SQL est de les jeter dans une table temporaire, et ensuite rejoint contre cela quand j'en avais besoin. J'ai donc fait la même chose dans Linq. J'ai donc fait la même chose avec Linq.
Dans mon fichier MyDB.dbml j'ajouté:
<Table Name="#temptab" Member="TempTabs">
<Type Name="TempTab">
<Column Name="recno" Type="System.Int32" DbType="Int NOT NULL"
IsPrimaryKey="true" CanBeNull="false" />
</Type>
</Table>
Ouverture du concepteur et fermer ajouté les entrées nécessaires là, bien que pour être complet, je vais citer le fichier MyDB.desginer.cs:
[Table(Name="#temptab")]
public partial class TempTab : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _recno;
#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnrecnoChanging(int value);
partial void OnrecnoChanged();
#endregion
public TempTab()
{
OnCreated();
}
[Column(Storage="_recno", DbType="Int NOT NULL", IsPrimaryKey=true)]
public int recno
{
get
{
return this._recno;
}
set
{
if ((this._recno != value))
{
this.OnrecnoChanging(value);
this.SendPropertyChanging();
this._recno = value;
this.SendPropertyChanged("recno");
this.OnrecnoChanged();
}
}
}
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SendPropertyChanging()
{
if ((this.PropertyChanging != null))
{
this.PropertyChanging(this, emptyChangingEventArgs);
}
}
protected virtual void SendPropertyChanged(String propertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Ensuite, il est devenu simplement question de jongler avec certaines choses dans le code. Là où je serais normalement dû:
MyDBDataContext mydb = new MyDBDataContext();
je devais le faire pour partager sa connexion avec un SqlConnection normale pour que je puisse utiliser la connexion pour créer la table temporaire. Après cela, il semble tout à fait utilisable.
string connstring = "Data Source.... etc..";
SqlConnection conn = new SqlConnection(connstring);
conn.Open();
SqlCommand cmd = new SqlCommand("create table #temptab " +
"(recno int primary key not null)", conn);
cmd.ExecuteNonQuery();
MyDBDataContext mydb = new MyDBDataContext(conn);
// Now insert some records (1 shown for example)
TempTab tt = new TempTab();
tt.recno = 1;
mydb.TempTabs.InsertOnSubmit(tt);
mydb.SubmitChanges();
Et l'utiliser:
// Through normal SqlCommands, etc...
cmd = new SqlCommand("select top 1 * from #temptab", conn);
Object o = cmd.ExecuteScalar();
// Or through Linq
var t = from tx in mydb.TempTabs
from v in mydb.v_BigTables
where tx.recno == v.recno
select tx;
Quelqu'un voit-il un problème avec cette approche comme une solution polyvalente pour l'utilisation de tables temporaires dans les jointures dans LINQ?
Il a résolu mon problème à merveille, comme maintenant je peux faire une jointure directe dans Linq au lieu d'avoir à utiliser .Contains().
Postscript: Le seul problème que j'ai est que le mélange LINQ et SqlCommands réguliers sur la table (où l'on est de lecture/écriture et est donc l'autre) peut être dangereux. Toujours en utilisant SqlCommands à insérer sur la table, puis les commandes Linq pour lire cela fonctionne bien. Apparemment, Linq met en cache les résultats - il y a probablement un moyen de contourner le problème, mais ce n'était pas évident.
Pour être honnête, je n'ai pas testé la solution que j'ai fournie en utilisant des tables temporaires. Cela étant dit, la solution fonctionnera certainement en utilisant des tables "permanentes". En outre, la raison pour laquelle j'utilise la méthode DataContext.ExecuteCommand() est que l'instruction SQL n'est pas du tout gérée par le moteur LINQ ... ce que vous envoyez est ce qui est exécuté. –