linq to sql - example - Clases de entidades desacopladas del proveedor de LINQ a SQL para implementar el patrón Repositorio. ¿Cómo?
linq to sql c# ejemplos (9)
Revisé el patrón del Repositorio y reconocí algunas ideas que estaba usando en el pasado que me hicieron sentir bien.
Sin embargo, ahora me gustaría escribir una aplicación que usaría este patrón, PERO ME GUSTARÍA DESCONECTAR LAS CLASES DE ENTIDAD del proveedor del repositorio.
Yo crearía varias asambleas:
- un ensamblado de "Interfaces" que albergaría interfaces comunes, incluida la interfaz IRepository
- un ensamblado de "Entidades" que albergaría las clases de entidad tales como Producto, Usuario, Orden, etc. El ensamblado "Interfaces" hace referencia a este conjunto, ya que algunos métodos devolverían dichos tipos o matrices. También sería referenciado por el ensamblaje de la aplicación principal (como la aplicación web)
- uno o más conjuntos / conjuntos de proveedor de repositorio. Cada uno incluiría (al menos) una clase que implementa la interfaz IRepository y funcionaría con un cierto Almacén de Datos. Los almacenes de datos podrían incluir un servidor SQL, un servidor Oracle, MySQL, archivos XML, servicios Web / WCF, etc.
Estudiar LINQ to SQL que parece muy productivo en términos de tiempo para implementar todo parece estar bien hasta que descubro la profunda dependencia entre las clases generadas y la clase CustomDataContext.
¿Cómo puedo usar LINQ to SQL en tal escenario?
¿Podrían las clases de su entidad implementar las interfaces IProduct, IUser, IOrder, etc. que se declararían en su ensamblado de "Interfaces"? De esta forma, la interfaz de IRepository hace referencia solo a las interfaces de objetos comerciales (es decir, devuelve colecciones de IProduct, etc.) y el ensamblaje "Interfaces" está desacoplado de los demás ensamblajes específicos de la implementación.
No es exactamente el mismo escenario, pero estoy trabajando para crear una herramienta personalizada que, en función de un archivo XML, genere un modelo OO. Mi enfoque es utilizar LINQ to SQL detrás de la escena y dado que estoy generando el código automáticamente, sería fácil usar otro mecanismo para digamos fuente de datos MySQL. Dado que no es compatible con LINQ to SQL, tendrá que escribir el código de acceso a datos manualmente, pero el código del cliente que utilizará el modelo OO cambiará de cualquier forma.
No sé si esto es exactamente lo que quiere, pero tal vez quiera echarle un vistazo al código MVC Storefront de Rob Conery. Utiliza una variante del patrón de repositorio con un proveedor de linq. Asigna los objetos LINQ a Sql a los objetos de dominio y luego devuelve los objetos de dominio del proveedor del repositorio a una capa de servicio que envuelve al proveedor, lo que le permite trabajar un poco de lógica en los datos devueltos antes de que llegue a la capa empresarial.
Webcasts de MVC Storefront
Código
Para mí, parece que desea que los proveedores devuelvan DTO y luego desea asignar los DTO a los objetos de dominio en la capa de repositorio / servicio. Si este es el caso, puede asignar su proveedor de LINQ a SQL a los DTO, haga que los devuelva, luego asigne los DTO a los objetos de dominio en la capa de repositorio / servicio. Esto debería funcionar bien, pero puede volverse tedioso ya que ahora tendría 2 capas de mapeo.
En este caso, tendría: ProductService, que toma un IProductRepository. Evoca métodos en el IProductRepository para recuperar sus DTO. A continuación, asigna los DTO a los objetos comerciales reales y los devuelve al código de llamada.
Creo que quieres compatibilidad con POCO (objetos CLR antiguos). LINQ to SQL tiene un adaptador llamado Close2Poco .
Pero les aconsejo que cambien a Entity Framework, en el momento en que también tienen un adaptador POCO , pero en v2 se espera que sea compatible de manera inmediata .
Hice algo similar con WCF
1 En su DBML, configure el modo de serialización en Unidireccional
2 Establezca TODAS las columnas en sus tablas para UpdateCheck = false
3 Escribe tu servicio de la siguiente manera:
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 Agregue una referencia de servicio
La forma más sencilla sería desacoplar sus entidades del contexto de datos: cargue la entidad necesaria, desacóplela de DataContext, úsela como prefiera, luego use Adjuntar () para acoplarla con un DataContext para guardar.
Tristemente LINQ no tiene un método para desacoplar entidades de un contexto de datos, pero puedes clonarlas, eso funciona muy bien. La forma más simple sería algo como esto:
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);
}
}
No tiene que usar el código generado LINQ to SQL, puede decorar sus propias clases con los atributos de columna necesarios o usar un archivo de asignación XML externo.
Puede crear un archivo XML externo asignando la base de datos a cualquier clase:
<?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>
Y luego pasa el XML a una clase 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;
}
}
Encontré una entrada de blog fantástica (con un montón de buen código) sobre esto aquí: http://iridescence.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx