Je sais que cela permet uniquement à la classe de le définir, mais à quoi ça sert?
Comment résoudre le problème des identifiants en lecture seule?
Disons que j'ai un cours individuel:
public class Person
{
public string Name { get; set; }
public int Id { get; private set; }
public int Age { get; set; }
}
Et c'est dans un Entities.dll
, utilisé par une interface graphique, BL et DAL.
L'interface graphique appelle le BL:
List<Person> p = BL.PeopleBL.GetPeople();
Pour les besoins de l'exemple appelle le DAL:
...
while(dr.read())
{
returnPersonList.add( new Person{ Age=dr.GetInt32(1), Id=dr.GetInt32(0), Name=dr.GetString(2)})
}
...
bien sûr, je ne peux pas faire ça car Id est un ensemble privé; Quelle est la bonne façon de procéder?
Comment puis-je laisser le BL/Dal définir l'ID, mais pas sur l'interface graphique?
Ou n'est-ce pas même la bonne utilisation d'un poste privé?
Je voulais juste ajouter qu'il s'agit de votre application DB typique, où le pk est l'ID et ne doit pas être modifié (uniquement par le BL/DAL)
C'est une solution possible mais pas très propre:
internal
BAL.dll
& DAL.dll
Visible interne dans assemblyinfo.cs
public class Person
{
public Person(int id)
{
this.Id=id;
}
public string Name { get; set; }
public int Id { get; internal set; }
public int Age { get; set; }
}
AssemblyInfo.cs
pour Entities.dll
[Assembly: InternalsVisibleTo("DAL"), InternalsVisibleTo("BAL")]
De cette façon, tous vos éléments internes seront visibles par DAL & BAL. Ce n'est peut-être pas souhaitable, mais je suggère simplement une solution possible.
Les deux approches courantes sont soit que la classe doit avoir un constructeur pour le DAL à utiliser, soit que le DAL doit utiliser la réflexion pour hydrater les objets.
Ou vous pouvez faire
public class Person
{
public Person(int id)
{
this.Id=id;
}
public string Name { get; set; }
public int Id { get; private set; }
public int Age { get; set; }
}
Peut-être que je me méprends, mais si vous voulez des identifiants vraiment en lecture seule, pourquoi ne pas utiliser un champ en lecture seule réel?
public class Person
{
public Person(int id)
{
m_id = id;
}
readonly int m_id;
public int Id { get { return m_id; } }
}
Vous pouvez laisser l'utilisateur définir une propriété en lecture seule en la fournissant via le constructeur:
public class Person
{
public Person(int id)
{
this.Id = id;
}
public string Name { get; set; }
public int Id { get; private set; }
public int Age { get; set; }
}
while(dr.read())
{
returnPersonList.add(
new Person(dr.GetInt32(1), dr.GetInt32(0), dr.GetString(2)));
}
où:
public class Person
{
public Person(int age, int id, string name)
{
Age = age;
Id = id;
Name = name;
}
}
Vous pouvez peut-être les marquer comme internes, et dans ce cas, seules les classes de votre DAL ou BL (en supposant qu'il s'agit de DLL distinctes) pourraient le définir.
Vous pouvez également fournir un constructeur qui prend les champs et les expose uniquement en tant que propriétés.
C'est normalement le cas, alors l'ID n'est pas une partie naturelle de l'entité, mais un artefact de base de données qui doit être retiré.
Il s'agit d'une décision de conception: autoriser uniquement la définition de l'ID pendant la construction ou via l'appel de méthode, il est donc géré en interne par la classe.
Vous pouvez écrire un setter vous-même, en supposant que vous avez un champ de support:
private int Id = 0;
public void SetId (int id)
{
this.Id = id;
}
Ou via un constructeur:
private int Id = 0;
public Person (int id)
{
this.Id = id;
}
Selon l'étendue de mon application, j'aime mettre les mécanismes d'hydratation de l'objet dans l'objet lui-même. Je vais envelopper le lecteur de données avec un objet personnalisé et lui passer un délégué qui sera exécuté une fois la requête retournée. Le délégué obtient le DataReader. Puis, puisque je suis dans mon objet commercial intelligent, je peux m'hydrater avec mes arrangeurs privés.
Le "DataAccessWrapper" encapsule toute la gestion de la connexion et du cycle de vie des objets pour moi. Ainsi, lorsque j'appelle "ExecuteDataReader", il crée la connexion, avec le processus passé (il y a une surcharge pour les paramètres), l'exécute, exécute le délégué puis nettoie après lui-même.
public class User
{
public static List<User> GetAllUsers()
{
DataAccessWrapper daw = new DataAccessWrapper();
return (List<User>)(daw.ExecuteDataReader("MyProc", new ReaderDelegate(ReadList)));
}
protected static object ReadList(SQLDataReader dr)
{
List<User> retVal = new List<User>();
while(dr.Read())
{
User temp = new User();
temp.Prop1 = dr.GetString("Prop1");
temp.Prop2 = dr.GetInt("Prop2");
retVal.Add(temp);
}
return retVal;
}
}