Classi di entità disaccoppiate dal provider LINQ al provider SQL per l'implementazione del modello di repository. Come?

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

Domanda

Ho esaminato il modello del repository e ho riconosciuto alcune idee che stavo usando in passato e che mi hanno fatto sentire bene.

Tuttavia ora vorrei scrivere un'applicazione che userebbe questo schema MA MI PIACCIONO AVERE LE CLASSI DI ENTITÀ DECOLLATE dal provider del repository.

Vorrei creare diversi assiemi:

  1. an " Interfaces " assembly che ospiterebbe interfacce comuni tra cui l'interfaccia IRepository
  2. un " Entità " assemblaggio che ospiterebbe le classi di entità come Prodotto, Utente, Ordine e così via. A questo assembly verrà fatto riferimento dalle "interfacce" assembly poiché alcuni metodi restituiscono tali tipi o matrici di essi. Inoltre verrebbe indicato dall'assembly dell'applicazione principale (come l'applicazione Web)
  3. uno o più assembly / assembly del provider del repository. Ciascuno includerebbe (almeno) una classe che implementa l'interfaccia IRepository e funzionerebbe con un determinato Data Store. Gli archivi dati potrebbero includere un server SQL, un server Oracle, MySQL, file XML, servizi Web / WCF e così via.

Studiare LINQ to SQL che sembra molto produttivo in termini di tempo impiegato per implementare tutto sembra andare bene finché non scopro la profonda dipendenza tra le classi generate e la classe CustomDataContext.

Come posso usare LINQ to SQL in un tale scenario?

È stato utile?

Soluzione

Non so se questo è esattamente quello che vuoi, ma potresti dare un'occhiata al codice MVC Storefront di Rob Conery. Usa una variante del modello di repository con un provider linq. Associa gli oggetti LINQ to Sql agli oggetti di dominio e quindi restituisce gli oggetti di dominio dal provider del repository a un livello di servizio che avvolge il provider consentendogli di lavorare una logica sui dati restituiti prima che colpisca il livello aziendale.

Webcast MVC Storefront
Codice

A me sembra che tu voglia che i provider restituiscano DTO e che tu voglia mappare i DTO agli oggetti del dominio nel livello repository / servizio. In tal caso, è possibile mappare il provider LINQ a SQL sui DTO, farli restituire, quindi mappare i DTO sugli oggetti di dominio nel livello repository / servizio. Questo dovrebbe funzionare bene, ma potrebbe diventare noioso come ora avresti 2 livelli di mappatura.

In questo caso avresti: ProductService, che accetta un IProductRepository. Richiama i metodi nel repository IProduct per recuperare i DTO. Quindi mappa i DTO sugli oggetti business reali e li restituisce al codice chiamante.

Altri suggerimenti

È possibile creare un file XML esterno che associa il database a qualsiasi 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>

E quindi passare l'XML a una 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;
     }
  }

Ho trovato un fantastico post sul blog (con un sacco di buon codice) su questo qui: http://iridescence.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx

Penso che tu voglia il supporto POCO (Plain Old CLR Objects). LINQ to SQL ha un adattatore chiamato Close2Poco .

Ma consiglierei di passare a Entity Framework, al momento hanno anche un adattatore POCO , ma in v2 dovrebbe essere supportato per impostazione predefinita .

Non è necessario utilizzare il codice generato da LINQ to SQL, è possibile decorare le proprie classi con i ColumnAttributes necessari o utilizzare un file di mapping XML esterno.

Il modo più semplice sarebbe quello di disaccoppiare le entità dal datacontext: caricare l'entità necessaria, disaccoppiarla da DataContext, usarla come preferisci, in seguito utilizzare Attach () per accoppiarla a DataContext per il salvataggio.

Sfortunatamente LINQ non ha un metodo per separare le entità da un datacontext, ma puoi semplicemente clonarle, che funzionano bene. Il modo più semplice sarebbe qualcosa di simile:

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);
  }
}

Ho fatto qualcosa di simile con WCF

1 Sul tuo DBML, imposta la modalità di serializzazione su Unidirezionale

2 Imposta TUTTE le colonne sulle tue tabelle su UpdateCheck = false

3 Scrivi il tuo servizio in modo simile al seguente:

   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 Aggiungi un riferimento al servizio

Non esattamente lo stesso scenario, ma sto lavorando per creare uno strumento personalizzato che basato su un file XML genererà un modello OO. Il mio approccio è quello di utilizzare LINQ to SQL dietro le quinte e dal momento che sto generando il codice automaticamente sarebbe facile usare un altro meccanismo per dire l'origine dati MySQL. Poiché non è supportato da LINQ to SQL, dovrai scrivere manualmente il codice di accesso ai dati, ma il codice client che utilizzerà il modello OO cambierà in alcun modo.

Le tue classi Entity potrebbero implementare interfacce IProduct, IUser, IOrder ecc. che sarebbero dichiarate nelle tue interfacce " montaggio? In questo modo l'interfaccia IRepository fa riferimento solo alle interfacce degli oggetti business (vale a dire, restituisce raccolte di IProduct ecc.) E le "interfacce" assembly viene disaccoppiato dagli altri assembly specifici dell'implementazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top