court Explication
Il semble que la partie de votre question qui peut sembler difficile est de savoir comment remplir une classe personnalisée de la même manière que la requête LINQ to SQL ("L2S" à partir de maintenant) pour la classe anonyme.
Sur la base de votre boucle foreach
Je devine vos classes personnalisées sont semblables à ceux-ci:
public class PostType
{
public int PostId { get; set; }
public List<PostComment> PostComments { get; set; }
}
public class PostComment
{
public int CommentId { get; set; }
public string Title { get; set; }
}
La requête LINQ devrait être équivalente à cette instruction T-SQL:
SELECT P.post_id, C.id, C.title
FROM post As P, comment As C
WHERE
P.post_id = @PostId
AND P.post_isdeleted = 0 -- 0 is false
AND C.CommentPostID = P.post_id
Contrairement au L2S version (voir la section Explication détaillée ci-dessous pour plus d'informations), cette instruction renvoie un résultat aplati avec chaque ligne contenant un P.post_id
, un C.id
et un C.title
. Si votre classe PostType
représentait une entrée de la même manière, cela aurait été facilement résolu (je ne préconise pas un tel design, je ne fais que commenter la façon dont le design modifie la façon dont il est peuplé). La relation hiérarchique dans les classes change les choses.
En outre, votre code a montré un List<PostType>
mais une liste n'est pas nécessaire car il y aura toujours un PostType
car vous filtrez sur post_id
.Si cette condition est supprimée, puis, vous pouvez obtenir plusieurs correspondances avec des PostIds différents lorsque les autres conditions sont remplies. Si c'est le cas, le code ci-dessous devrait changer. Cela dit, sautons dans ADO.NET et peuplons les classes en utilisant un SqlDataReader.
int postIdInput = 42; // desired post_id to search for
// PostType delcared prior to getting the results
PostType postType = new PostType()
{
PostId = postIdInput,
PostComments = new List<PostComment>()
};
// Database interaction starts here...
// updated SQL statement to use column name aliases for clarity when used by the SqlDataReader
string sqlStatement = @"SELECT P.post_id As PostId, C.id As CommentId, C.title As Title
FROM post As P, comment As C
WHERE
P.post_id = @PostId
AND P.post_isdeleted = 0 -- 0 is false
AND C.CommentPostID = P.post_id";
string sqlConnectionString = "..."; // whatever your connection is... probably identical to your L2S context.Connection.ConnectionString
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
SqlCommand command = new SqlCommand(sqlStatement, conn);
command.Parameters.AddWithValue("@PostId", postIdInput); // use Parameters.Add() for greater specificity
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
// postId was set based on input, but could be set here as well although it would occur repeatedly
// if desired, uncomment the 2 lines below and there's no need to initialize it earlier (it'll be overwritten anyway)
//int postId = Int32.Parse(reader["PostId"].ToString());
//postType.PostId = postId;
int commentId = Int32.Parse(reader["CommentId"].ToString());
string title = reader["Title"].ToString();
// add new PostComment to the list
PostComment postComment = new PostComment
{
CommentId = commentId,
Title = title
};
postType.PostComments.Add(postComment);
}
// done! postType is populated...
}
// use postType...
Cela devrait couvrir votre scénario. Cependant, pour une réponse beaucoup plus détaillée, continuez à lire!
Explication détaillée (alias « Enseignez un homme à pêcher ... »)
Disons que vous ne pourriez pas comprendre comment obtenir l'équivalent instruction SQL. Bien qu'il existe différentes façons de le faire, je vais me concentrer sur le fait que vous utilisez L2S et explorer certaines options connexes.
Étape 1: Conversion de la requête LINQ to SQL (par "tricherie")
Vous avez de la chance car il y a un raccourci. La conversion de votre expression LINQ existante en SQL est une situation un peu plus pratique que de revenir en arrière et de traduire SQL en LINQ.
Vous pouvez obtenir l'instruction T-SQL traduit à partir de votre code en utilisant l'une de ces options DataContext:
NOTE: J'ai dit c'était un raccourci. La connaissance de SQL est bonne à connaître, et pour être clair, je ne suggère pas l'utilisation de la production générée à l'aveuglette. Certes, le SQL peut différer de ce que vous attendez parfois, néanmoins il fournit un point de départ décent. Vous pouvez le modifier si nécessaire.
Utilisez l'une de ces méthodes et copiez le résultat - vous en aurez besoin pour Étape 2.
Exemple DataContext.GetCommand() utilisation:
var query = /* your L2S query here */;
string sqlStatement = context.GetCommand(query).CommandText; // voila!
Pour obtenir le résultat soit mis un point d'arrêt et de copier sa valeur, vérifiez dans la fenêtre immédiate, ou l'afficher quelque part (Console.WriteLine etc.).
Exemple d'utilisation DataContext.Log:
context.Log = Console.Out;
requêtes exécutées sur ce contexte auront leurs instructions SQL sous-évaluées à la fenêtre de la console. Vous pouvez le copier à partir de là.Pour les jeter ailleurs, comme à la fenêtre de sortie de débogage, consultez ces liens:
Etape 2: Avec l'instruction SQL en main , utilisez-le dans ADO.NET
Maintenant que vous avez l'instruction SQL, nous pouvons l'utiliser dans ADO.NET. Bien sûr, vous pouvez aussi utiliser une procédure stockée et il ne devrait pas être difficile de la remplacer.
Avant de l'utiliser, vous souhaiterez probablement nettoyer l'instruction. J'ai utilisé une requête similaire au niveau local pour obtenir cette déclaration et votre produit ressemble probablement ceci:
SELECT [t0].[post_id], [t1].[id], [t1].[title], (
SELECT COUNT(*)
FROM [comment] AS [t2]
WHERE [t2].[id] = [t0].[post_id]
) As [value]
FROM [post] As [t0]
LEFT OUTER JOIN [comment] As [t1] ON [t1].[CommentPostID] = [t0].[post_id]
WHERE ([t0].[post_id] = @p0) AND ([t0].[post_isdeleted] = 0)
ORDER BY [t0].[post_id], [t1].[id]
Notez que le SELECT COUNT intégré (*)? La requête L2S n'a jamais demandé le nombre, mais le résultat demande le nombre d'ID identiques utilisés sur la jointure. Notez également qu'il n'y a pas d'alias pour les colonnes. Vous devez vous référer aux colonnes en fonction de leurs noms réels (par exemple post_id
par rapport à PostId
). De plus, les paramètres SQL sont nommés @ p0 ... @ pn et un ordre de tri par défaut est appliqué. Vous pouvez copier/coller ceci dans le SqlDataReader utilisé précédemment, mais vous devrez renommer les colonnes et les paramètres à faire correspondre.
A nettoyé la version de ce qui précède est reproduit ci-dessous avec les paramètres rebaptisés et pièces inutiles sont commentées (si cette approche est prise tester pour vous assurer qu'il est équivalent à ce qui est prévu):
SELECT [P].[post_id] As PostId, [C].[id] As CommentId, [C].[title] As Title--, (
-- SELECT COUNT(*)
-- FROM [comment] AS [t2]
-- WHERE [t2].[id] = [t0].[post_id]
--) As [value]
FROM [post] As [P]
LEFT OUTER JOIN [comment] As [C] ON [C].[CommentPostID] = [P].[post_id]
WHERE ([P].[post_id] = @PostId) AND ([P].[post_isdeleted] = 0)
--ORDER BY [t0].[post_id], [t1].[id]
ci-dessus peut maintenant être utilisé avec le SqlDataReader de plus tôt.
Une requête plus directe aurait pu être générée si la requête L2S était dans le format d'un SelectMany, tels que:
var query = from arow in context.post
from c in context.comment
where arow.post_id == id && arow.post_isdeleted == false
&& c.CommentPostID == arow.post_id
select new
{
arow.post_id,
c.id,
c.title
};
La requête SelectMany L2S génère une instruction SQL similaire à ceci:
SELECT [t0].[post_id], [t1].[id], [t1].[title]
FROM [post] As [t0], [comment] As [t1]
WHERE ([t0].[post_id] = @p0) AND ([t0].[post_isdeleted] = 0)
AND ([t1].[CommentPostID] = [t0].[post_id])
LINQPad
Bien que cette explication détaillée peut sembler écrasante, il y a une moyen facile d'avoir cette information à portée de main. Si vous n'avez pas donné LINQPad un essai alors je le recommande fortement - c'est gratuit aussi! LINQPad vous montrera les résultats de vos requêtes L2S, a un onglet SQL pour voir le SQL généré, et montre également l'expression lambda utilisée (la syntaxe de la requête ci-dessus est représentée par l'équivalent lambda/extension). En plus de cela, c'est un excellent outil pour C#/VB.NET généraliste (y compris LINQ to Objects/XML), et le codage SQL avec support de base de données et bien plus encore.
Voici une capture d'écran minuscule de LINQPad montrant quelques-uns des sujets abordés précédemment:
Je ne voulais pas prendre plus Page Immobiliere que moi déjà si click here to see the image in its original size.
Si vous l'avez fait jusqu'ici, félicitations!:)
Quel sql utilisez-vous? Si vous utilisez t-sql, la réponse ne sera pas la même que si vous utilisiez plsql. – ALOToverflow
J'utilise SQL Server – Luke101