Les classes d'entités découplées du fournisseur LINQ to SQL pour l'implémentation du modèle de référentiel. Comment?

StackOverflow https://stackoverflow.com/questions/229627

Question

J'ai examiné le modèle de référentiel et j'ai reconnu certaines idées que j'utilisais dans le passé qui m'ont fait sentir bien.

Cependant, j'aimerais maintenant écrire une application qui utiliserait ce modèle MAIS JE VOUDRAIS QUE LES CLASSES D'ENTITÉ SOIENT DÉCOUPLÉES du fournisseur de référentiel.

Je créerais plusieurs assemblys:

  1. an " Interfaces " assembly qui hébergerait des interfaces communes, y compris l'interface IRepository
  2. an " Entités " assemblage qui hébergerait les classes d’entités telles que Product, User, Order, etc. Cet assemblage serait référencé par le lien "Interfaces". assemblage car certaines méthodes renverraient de tels types ou tableaux. En outre, il serait référencé par l’assemblage principal de l’application (telle que l’application Web)
  3. un ou plusieurs assemblage (s) fournisseur (s) de référentiel. Chacune inclurait (au moins) une classe qui implémenterait l'interface IRepository et fonctionnerait avec un certain magasin de données. Les magasins de données peuvent inclure un serveur SQL, un serveur Oracle, MySQL, des fichiers XML, des services Web / WCF, etc.

L'étude de LINQ to SQL, qui semble très productive en termes de temps d'implémentation, semble bien aller jusqu'à ce que je découvre la dépendance profonde entre les classes générées et la classe CustomDataContext.

Comment utiliser LINQ to SQL dans un tel scénario?

Était-ce utile?

La solution

Je ne sais pas si c'est exactement ce que vous voulez, mais vous voudrez peut-être jeter un coup d'œil au code de MVC Storefront de Rob Conery. Il utilise une variante du modèle de référentiel avec un fournisseur linq. Il mappe les objets LINQ to Sql aux objets de domaine, puis renvoie les objets de domaine du fournisseur de référentiel à une couche de service qui englobe le fournisseur, ce qui lui permet de manipuler les données renvoyées avant qu'elles n'atteignent la couche de gestion.

diffusions Web de la vitrine de MVC
Code

Pour moi, il semblerait que vous souhaitiez que les fournisseurs renvoient des DTO, puis que vous souhaitiez mapper les DTO aux objets de domaine de la couche référentiel / service. Si tel est le cas, vous pouvez mapper votre fournisseur LINQ to SQL sur les DTO, le renvoyer, puis mapper les DTO sur des objets de domaine dans la couche référentiel / service. Cela devrait fonctionner correctement, mais cela peut devenir fastidieux car vous auriez maintenant deux couches de mappage.

Dans ce cas, vous auriez: ProductService, qui prend un IProductRepository. Il évoque les méthodes sur IProductRepository pour récupérer vos DTO. Il associe ensuite les DTO aux objets métier réels et les renvoie au code appelant.

Autres conseils

Vous pouvez créer un fichier XML externe mappant la base de données sur n’importe quelle classe:

 <?xml version="1.0" encoding="utf-8"?>
 <Database Name="DbName" 
           xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
    <Table Name="DbTableName">
       <Type Name="EntityClassName" >
           <Column Name="ID" Type="System.Int64" Member="Id"
                   DbType="BigInt NOT NULL IDENTITY" IsPrimaryKey="true"
                   CanBeNull="false" />
           <Column Name="ColumnName" Type="System.String" Member="PropertyA"
                   DbType="VarChar(1024)" CanBeNull="true" />
       </Type>
    </Table>
 </Database>

Et passez ensuite le code XML à une classe DataContext:

 using (var cn = GetDbConnection())
  { var mappingSrc = XmlMappingSource.FromReader(xmlReader);

    using (var db = new DataContext(cn, mappingSrc))
     { var q = from entity in db.GetTable<EntityClassName>()
               where entity.PropertyA = "..."
               select entity.ID;
     }
  }

J'ai trouvé un article de blog fantastique (avec beaucoup de bon code) à ce sujet ici: http://iridescence.no/post/Linq-to-Sql-Programming-Against-Interface-and-the-Repository-Pattern.aspx

Je pense que vous voulez le support de POCO (Plain Old CLR Objects). LINQ to SQL a un adaptateur appelé Close2Poco .

Mais je vous conseillerais de passer à Entity Framework. Pour le moment, ils disposent également d’un adaptateur POCO , mais dans v2 devrait être pris en charge immédiatement .

Vous n'avez pas besoin d'utiliser le code généré par LINQ to SQL, vous pouvez décorer vos propres classes avec les ColumnAttributes nécessaires ou utiliser un fichier de mappage XML externe.

Le moyen le plus simple serait de découpler vos entités du datacontext: chargez l'entité requise, découplez-la du DataContext, utilisez-la comme bon vous semble, utilisez plus tard Attach () pour l'associer à un DataContext pour la sauvegarde.

Malheureusement, LINQ n’a aucune méthode pour découpler des entités d’un contexte de données, mais vous pouvez simplement les cloner, cela fonctionne bien. Le moyen le plus simple serait quelque chose comme ceci:

public static T CloneEntity<T>(T source)
{
  DataContractSerializer dcs = new DataContractSerializer(typeof(T));
  using (Stream stream = new MemoryStream())
  {
    dcs.WriteObject(stream, source);
    stream.Seek(0, SeekOrigin.Begin);
    return (T)dcs.ReadObject(stream);
  }
}

J'ai fait quelque chose de similaire avec WCF

1 Sur votre DBML, définissez le mode de sérialisation sur Unidirectionnel

.

2 Définissez TOUTES les colonnes de vos tables sur UpdateCheck = false

.

3 Ecrivez votre service à peu près comme suit:

   public class Service1 : IService1
    {
        public Company GetCompany(int companyId)
        {
            using (DataClasses1DataContext dc = new DataClasses1DataContext())
            {
                return (from c in dc.Companies where c.CompanyId == companyId select c).Single();
            }
        }

    public void SaveCompany(Company company)
    {
        using (DataClasses1DataContext dc = new DataClasses1DataContext())
        {
            dc.Companies.Attach(company, true);
            dc.SubmitChanges();
        }
    }

    public void InsertCompany(Company company)
    {
        using (DataClasses1DataContext dc = new DataClasses1DataContext())
        {
            dc.Companies.InsertOnSubmit(company);
            dc.SubmitChanges();
        }
    }
}

4 Ajouter une référence de service

Ce n'est pas exactement le même scénario, mais je travaille à la création d'un outil personnalisé basé sur un fichier XML qui générera un modèle OO. Mon approche consiste à utiliser LINQ to SQL en coulisse et, comme je génère le code automatiquement, il serait facile d’utiliser un autre mécanisme pour les sources de données MySQL, par exemple. Comme il n'est pas pris en charge par LINQ to SQL, vous devrez écrire le code d'accès aux données manuellement, mais le code client qui utilisera le modèle OO changera de quelque manière que ce soit.

Vos classes d'entité pourraient-elles implémenter des interfaces IProduct, IUser, IOrder, etc., qui seraient déclarées dans votre " Interfaces " Assemblée? De cette manière, l’interface IRepository ne fait référence qu’aux interfaces d’objet métier (c’est-à-dire renvoie des collections de produits IP, etc.) et à la section "Interfaces". l'assemblage est découplé de vos autres assemblys spécifiques à l'implémentation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top