Emballage DbSet & lt; TEntity & gt; avec un DbSet / IDbSet personnalisé?
Tout d'abord, je pense que c'est un peu ridicule de le faire mais les autres membres de mon équipe insister sur elle et je ne peux pas venir avec un bon argument contre elle d'autre que "je pense que c'est stupide"...
Ce que nous essayons de faire est de créer un complètement abstraite de la couche de données et ensuite les différentes implémentations de cette couche de données. Assez Simple, non? Entrez Entity Framework 4.1...
Au final, notre objectif, ici, est que les programmeurs (je fais de mon mieux pour ne rester que sur la couche de données) ne veux plus jamais être exposés à des classes concrètes. Ils ne veulent jamais avoir à utiliser des interfaces dans leur code, à part évidemment avoir besoin d'instancier l'usine.
Je veux arriver à quelque chose comme ce qui suit:
D'abord, nous avons notre "Commune" de la bibliothèque de toutes les interfaces, nous allons l'appeler "Commun.De données":
public interface IEntity
{
int ID { get; set; }
}
public interface IUser : IEntity
{
int AccountID { get; set; }
string Username { get; set; }
string EmailAddress { get; set; }
IAccount Account { get; set; }
}
public interface IAccount : IEntity
{
string FirstName { get; set; }
string LastName { get; set; }
DbSet<IUser> Users { get; set; } //OR IDbSet<IUser> OR [IDbSet implementation]?
}
public interface IEntityFactory
{
DbSet<IUser> Users { get; }
DbSet<IAccount> Accounts { get; }
}
Depuis que nous avons ensuite une mise en œuvre de la bibliothèque, nous allons l'appeler "quelque Chose.Les données.Imp":
internal class User : IUser
{
public int ID { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public IAccount Account { get; set; }
public class Configuration : EntityTypeConfiguration<User>
{
public Configuration() : base()
{
...
}
}
}
internal class Account : IAccount
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DbSet<IUser> Users { get; set; } //OR IDbSet<IUser> OR [IDbSet implementation]?
public class Configuration : EntityTypeConfiguration<Account>
{
public Configuration() : base()
{
...
}
}
}
Usine:
public class ImplEntityFactory : IEntityFactory
{
private ImplEntityFactory(string connectionString)
{
this.dataContext = new MyEfDbContext(connectionString);
}
private MyEfDbContext dataContext;
public static ImplEntityFactory Instance(string connectionString)
{
if(ImplEntityFactory._instance == null)
ImplEntityFactory._instance = new ImplEntityFactory(connectionString);
return ImplEntityFactory._instance;
}
private static ImplEntityFactory _instance;
public DbSet<IUser> Users //OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Users; }
}
public DbSet<IAccount> Accounts //OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Accounts; }
}
}
Contexte:
public class MyEfDataContext : DbContext
{
public MyEfDataContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer<MyEfDataContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new User.Configuration());
modelBuilder.Configurations.Add(new Account.Configuration());
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
}
Puis le front-end programmeurs serait de l'utiliser comme:
public class UsingIt
{
public static void Main(string[] args)
{
IEntityFactory factory = new ImplEntityFactory("SQLConnectionString");
IUser user = factory.Users.Find(5);
IAccount usersAccount = user.Account;
IAccount account = factory.Accounts.Find(3);
Console.Write(account.Users.Count());
}
}
Donc c'est assez bien... j'espère que quelqu'un ici peut-être pouvoir me pointer dans la bonne direction ou aider à m'en sortir avec un bon argument que je peux le feu à l'équipe de développement. J'ai regardé quelques autres articles sur ce site concernant l'EF ne pas être en mesure de travailler avec des interfaces et une réponse dire que vous ne pouvez pas mettre en œuvre IDbSet
(que je trouve un peu curieux, pourquoi auraient-ils fournir si vous ne pouvais pas la mettre en œuvre?) mais jusqu'à présent sans succès.
Merci d'avance pour toute aide!
J
source d'informationauteur Jason
Vous devez vous connecter pour publier un commentaire.
Le premier argument est que les EF ne fonctionne pas avec les interfaces.
DbSet
doivent être définis avec une entité réelle mise en œuvre.Le deuxième argument est que les entités ne doivent pas contenir de
DbSet
- c'est-contexte lié classe et de vos entités doit être pur de cette dépendance à moins que vous allez mettre en œuvre Active modèle d'enregistrement. Même dans ce cas, vous n'aurez certainement pas avoir accès àDbSet
de différents entité à une autre entité. Même si vous mettez ensemble, vous êtes toujours trop près de l'EF et de l'entité n'ont jamais la propriété d'accéder à toutes les entités d'un autre type d'entité (pas seulement celles liées à l'instance en cours).Juste pour rendre les choses claires
DbSet
en EF a une signification très spéciale - ce n'est pas une collection. Il est le point d'entrée de base de données (par exemple chaque requête LINQ surDbSet
hits de la base de données) et c'est dans la normale des scénarios n'est pas exposé sur les entités.Le troisième argument est que vous utilisez un seul contexte par l'application que vous avez une seule instance privée par singleton, factory. Sauf si vous faites partie seule application batch il est vraiment mauvais.
La dernière argument est tout simplement pratique. Vous êtes payé pour la livraison de fonctionnalités ne sont pas une perte de temps et d'abstraction qui ne donnent pas de vous (et votre client) toute la valeur de l'entreprise. Il ne s'agit pas de prouver pourquoi vous ne devez pas créer cette abstraction. C'est à propos de prouver pourquoi vous devriez le faire. Quelle est la valeur que vous obtenez de l'aide? Si vos collègues ne sont pas en mesure de venir avec des arguments qui ont la valeur de l'entreprise, vous pouvez simplement aller à votre chef de produit et de lui laisser utiliser son pouvoir -, il détient le budget.
Généralement abstraction est la partie de bien conçu orientée objet de la demande - qui est correct. MAIS:
Quand il judicieux de faire "beaucoup de" l'abstraction?
Si vous travaillez uniquement l'application ciblée (pour la plupart de simples applications à la demande ou de solutions externalisées) l'abstraction devrait être utilisé seulement en cas de besoin. Ces applications sont influencés par les coûts - l'objectif est de générer de la solution de travail pour un minimum de frais et dans les plus brefs délais. Cet objectif doit être atteint, même si elle résulte de l'application ne sera pas très bonne à l'interne, la seule chose qui importe, c'est si l'application répond aux exigences. Toute abstraction basée sur "que faire si ... arrive" ou "peut-être que nous aurons besoin de ..." augmente les coûts par virtuel (non existant) les exigences qui seront à 99% de ne jamais arriver et dans la plupart des cas contrat initial avec le client n'a pas tenu compte de laquelle ces coûts supplémentaires.
Btw. ce type d'applications est ciblée par MME Api et concepteur de la stratégie - MS va faire beaucoup de concepteurs et de générateurs de code qui permettra de créer non optimale, mais pas cher et rapide de solutions qui peuvent être créées par des personnes ayant un plus petit ensemble de compétences et sont très bon marché. Le dernier exemple est LightSwitch.