Je mets à jour cette réponse parce que les commentaires laissés par les Developr semblent indiquer qu'il aimerait un peu plus de détails.
La réponse courte à votre question est Oui , vous aurez envie d'utiliser des instances de classes (objets) à la médiation de l'interface entre votre INTERFACE utilisateur et votre Entreprise de la Couche Logique. La BLL et DAL communiquer comme discuté ci-dessous. Vous ne devriez pas être en train de passer SqlDataTables ou SqlDataReaders autour.
La simple raisons: les objets sont de type sécurisé, offre de prise en charge Intellisense, vous permettre d'effectuer des ajouts ou des modifications à la Couche de gestion qui ne sont pas nécessairement trouvé dans la base de données, et vous donner une certaine liberté pour dissocier l'application à partir de la base de données de sorte que vous pouvez conserver une cohérence BLL interface de même que les modifications de base de données (dans les limites, bien sûr). Il est tout simplement bien pratique.
La grande image, c'est que, pour n'importe quelle page de votre INTERFACE, vous aurez un ou plusieurs "modèles" que vous souhaitez afficher et d'interagir avec. Les objets sont le moyen de capturer l'état actuel d'un modèle. En termes de processus: l'INTERFACE utilisateur demande un modèle (qui peut être un objet unique ou une liste d'objets) de la Couche de Logique (BLL). La BLL puis crée et renvoie de ce modèle, généralement en utilisant les outils de la Couche d'Accès aux Données (DAL). Si des modifications sont apportées au modèle dans l'INTERFACE utilisateur, puis l'INTERFACE utilisateur enverra la version révisée de l'objet(s) à la BLL avec des instructions pour savoir quoi faire avec eux (par exemple, insert, update, delete).
.NET est idéal pour ce genre de Séparation des Préoccupations, car le conteneur Générique classes - et en particulier de la Liste<> classe - sont parfaits pour ce genre de travail. Non seulement ils vous permettent de transmettre les données, mais elles sont facilement intégrés avec des contrôles d'INTERFACE utilisateur, comme les grilles, listes, etc. via l'ObjectDataSource classe. Vous pouvez mettre en œuvre toute la gamme des opérations que vous avez besoin pour développer l'INTERFACE utilisateur à l'aide ObjectDataSource: "Remplir" les opérations avec les paramètres, les opérations CRUD, tri, etc.).
Parce que c'est assez important, permettez-moi de faire un rapide détournement de démontrer comment définir un ObjectDataSource:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetArticles"
OnObjectCreating="OnObjectCreating"
TypeName="MotivationBusinessModel.ContentPagesLogic">
<SelectParameters>
<asp:SessionParameter DefaultValue="News" Name="category"
SessionField="CurPageCategory" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
Ici, MotivationBusinessModel est l'espace de noms pour la BLL et ContentPagesLogic est la classe la mise en œuvre de la logique, eh bien, les Pages de Contenu. La méthode pour l'extraction de données est "GetArticles" et il prend un Paramètre, appelé CurPageCategory. Dans ce cas particulier, l'ObjectDataSource renvoie une liste d'objets qui est ensuite utilisé par une grille. Notez que j'ai besoin de passer des informations d'état de session pour la BLL de la classe, dans le code derrière, j'ai une méthode "OnObjectCreating" qui me permet de créer l'objet et le passer dans les paramètres:
public void OnObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = new ContentPagesLogic(sessionObj);
}
Donc, c'est comment cela fonctionne. Mais cela soulève une question très importante - d'où viennent les Modèles d'Affaires / Objets proviennent? Orm comme Linq to SQL et Subsonique offrir des générateurs de code qui vous permettent de créer une classe pour chacun de vos tables de base de données. Qui est, ces outils de dire que les classes du modèle doit être défini dans votre DAL et la carte directement sur les tables de base de données. Linq to entities permet de définir des objets de manière tout à fait distincte de la mise en page de votre base de données, mais est d'autant plus complexe (c'est pourquoi il y a une distinction entre Linq to SQL et Linq to entities). En essence, c'est un BLL solution. Joel et je l'ai dit en divers endroits sur ce fil que, vraiment, la Couche de gestion est généralement là où les Modèles devraient être définis (bien que j'utilise un mélange de BLL et DAL objets dans la réalité).
Une fois que vous décidez de le faire, comment voulez-vous mettre en œuvre la cartographie à partir de modèles de la base de données? Eh bien, vous écrire des classes dans la BLL pour extraire les données (à l'aide de votre DAL) et de remplissage de l'objet ou de la liste d'objets. Il est Logique d'Entreprise parce que la correspondance est souvent accompagnée par de la logique supplémentaire pour étoffer le Modèle (par exemple, la définition de la valeur de la dérivée de champs).
Joel crée statique classes Usine pour mettre en œuvre le modèle de base de données de cartographie. C'est une bonne approche, car il utilise un modèle bien connu et des lieux de la mise en correspondance dans la construction de l'objet(s) doit être retourné. Vous savez toujours où aller pour voir de la cartographie et de l'approche globale est simple et directe.
J'ai pris une approche différente. Tout au long de ma BLL, je définir la Logique des classes et le Modèle de classes. Ceux-ci sont généralement définies dans des couples où les deux classes sont définies dans le même fichier, et dont les noms diffèrent par leur suffixe (par exemple ClassModel et ClassLogic). La Logique des classes à savoir comment travailler avec les classes du Modèle, faire des choses comme la Remplir, Enregistrer ("Upsert"), de Supprimer et de générer un retour pour une Instance du Modèle.
En particulier, de ne le Remplir, j'ai tirer parti des méthodes de trouver dans mon primaire DAL classe (voir ci-dessous) que permettez-moi de prendre toute classe et de toute requête SQL et de trouver un moyen de créer/remplir les instances de la classe en utilisant les données renvoyées par la requête (soit comme une instance unique ou comme une liste). C'est la Logique de la classe, juste attrape un Modèle de définition de classe, définit une Requête SQL et les envoie à la DAL. Le résultat est un objet unique ou une liste des objets que je peux alors passer à l'INTERFACE utilisateur. Notez que la requête peut retourner les champs d'une table ou plusieurs tables jointes ensemble. Au niveau de la cartographie, je n'ai vraiment pas de soins - je veux juste que certains objets remplis.
Voici la première fonction. Il faudra un arbitraire de la classe et de l'associer automatiquement à tous les champs de couplage extraites à partir d'une requête. La mise en correspondance est effectuée par trouver des champs dont le nom correspond à une propriété dans la classe. Si il y a des champs de la classe (par exemple celles que vous pourrez remplir à l'aide de la logique d'entreprise) ou extra champs de la requête, ils sont ignorés.
public List<T> ReturnList<T>() where T : new()
{
try
{
List<T> fdList = new List<T>();
myCommand.CommandText = QueryString;
SqlDataReader nwReader = myCommand.ExecuteReader();
Type objectType = typeof (T);
PropertyInfo[] typeFields = objectType.GetProperties();
if (nwReader != null)
{
while (nwReader.Read())
{
T obj = new T();
for (int i = 0; i < nwReader.FieldCount; i++)
{
foreach (PropertyInfo info in typeFields)
{
// Because the class may have fields that are *not* being filled, I don't use nwReader[info.Name] in this function.
if (info.Name == nwReader.GetName(i))
{
if (!nwReader[i].Equals(DBNull.Value))
info.SetValue(obj, nwReader[i], null);
break;
}
}
}
fdList.Add(obj);
}
nwReader.Close();
}
return fdList;
}
catch
{
conn.Close();
throw;
}
}
Il est utilisé dans le contexte de ma DAL mais la seule chose que vous devez avoir dans le DAL classe est un support pour la chaîne de Requête, à un objet SqlCommand avec une Connexion ouverte et de tous les paramètres. La clé est juste pour s'assurer que le ExecuteReader fonctionne lorsque cela s'appelle. Une utilisation typique de cette fonction par mon BLL donc ressemble:
return qry.Command("Select AttendDate, Count(*) as ClassAttendCount From ClassAttend")
.Where("ClassID", classID)
.ReturnList<AttendListDateModel>();
Vous pouvez également mettre en place un soutien pour les classes comme suit:
public List<T> ReturnList<T>(T sample)
{
try
{
List<T> fdList = new List<T>();
myCommand.CommandText = QueryString;
SqlDataReader nwReader = myCommand.ExecuteReader();
var properties = TypeDescriptor.GetProperties(sample);
if (nwReader != null)
{
while (nwReader.Read())
{
int objIdx = 0;
object[] objArray = new object[properties.Count];
for (int i = 0; i < nwReader.FieldCount; i++)
{
foreach (PropertyDescriptor info in properties) // FieldInfo info in typeFields)
{
if (info.Name == nwReader.GetName(i))
{
objArray[objIdx++] = nwReader[info.Name];
break;
}
}
}
fdList.Add((T)Activator.CreateInstance(sample.GetType(), objArray));
}
nwReader.Close();
}
return fdList;
}
catch
{
conn.Close();
throw;
}
}
Un appel à cette fonction ressemble à:
var qList = qry.Command("Select QueryDesc, UID, StaffID From Query")
.Where("SiteID", sessionObj.siteID)
.ReturnList(new { QueryDesc = "", UID = 0, StaffID=0 });
Maintenant qList est une liste générique de créé dynamiquement des instances de classe définie sur la volée.
Disons que vous avez une fonction dans votre BLL qui prend une liste déroulante comme un argument et une demande de remplir la liste de données. Voici comment vous pouvez remplir le tirer vers le bas avec les résultats extraits ci-dessus:
foreach (var queryObj in qList)
{
pullDownList.Add(new ListItem(queryObj.QueryDesc, queryObj.UID.ToString()));
}
En bref, nous pouvons définir anonymes Modèle d'Affaires classes à la volée, et puis les remplir seulement par le passage d'un nombre (à la volée) SQL à la DAL. Ainsi, la BLL est très facile de mettre à jour en réponse à l'évolution des besoins dans l'INTERFACE utilisateur.
Une dernière remarque: Si vous êtes inquiet que la définition et la passant autour des objets des déchets de la mémoire, vous ne devriez pas être: si vous utilisez un SqlDataReader pour extraire les données et de les placer dans les objets qui composent votre liste, vous n'aurez qu'une copie en mémoire (la liste) que le lecteur parcourt en lecture seule, suivant la mode. Bien sûr, si vous utilisez DataAdapter et le Tableau des classes (etc.) lors de votre couche d'accès aux données, alors vous serait il va sans encourir de frais généraux (qui est pourquoi vous ne devriez pas le faire).