9

我已经浏览了Repository模式,并且认识到我过去使用的一些想法让我感觉很好。实体类与LINQ to SQL提供程序分离以实现Repository模式。怎么样?

但是现在我想编写一个应用程序,使用这种模式但我想从实体库提供者那里获得实体类DECOUPLODED

我想创建几个组件:

  1. 一个“接口”组件,其将主办常用接口包括IRepository接口
  2. 一个“实体”组件,其将主办实体类如产品,用户,订单等。这个程序集将被“Interfaces”程序集引用,因为有些方法会返回这些类型或它们的数组。另外它还会被主应用程序组件(如Web应用程序)引用一个或多个存储库提供程序组合件/组件。每个包括(至少)一个实现IRepository接口的类,并且它将与某个Data Store一起工作。数据存储可能包括SQL Server,Oracle服务器,MySQL,XML文件,Web/WCF服务等。

研究LINQ to SQL在实现所有时间方面看起来非常高效,直到我发现生成的类和CustomDataContext类之间的深度依赖关系为止。

如何在这种情况下使用LINQ to SQL?

+0

本博客文章提出了一个很好的解决方案。 http://iridescence.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx – Riko 2009-08-21 13:30:37

+0

我已经实现了你所要求的,并将代码发布在我的博客:[一个通用的Linq到用于断开连接的Linq到SQL数据层的SQL库基类](http://devermind.com/linq/updated-generic-base-class-for-linq2sql-data-layers) – 2009-08-17 08:20:29

回答

6

我不知道这是否正是你想要的,但你可能想看看Rob Conery的MVC店面代码。他使用linq提供程序使用存储库模式的变体。他将LINQ to Sql对象映射到域对象,然后将域对象从存储库提供程序返回到服务层,该服务层封装了提供程序,允许他在返回到业务层之前返回数据的逻辑。

MVC Storefront Webcasts
Code

对我来说,这听起来像你想的供应商返回的DTO,然后你要到的DTO在仓库/业务层域对象映射。如果是这种情况,您可以将您的LINQ to SQL提供程序映射到DTO,让它返回它们,然后将DTO映射到存储库/服务层中的域对象。这应该工作得很好,但它可能会变得乏味,因为你现在有2个映射层。

在这种情况下,您将拥有: ProductService,它接受一个I​​ProductRepository。它唤起了IProductRepository中的方法来取回你的DTO。然后它将DTO映射到真实的业务对象并将它们返回给调用代码。

+0

我刚进去看看MVC店面。它们使用不同于LINQ自动生成的域对象。所以我可能也会这样做。感谢您指出这一点:) – 2008-10-25 23:17:29

1

不完全相同的情况,但我正在创建一个基于XML文件的自定义工具将生成一个OO模型。我的方法是在场景后面使用LINQ to SQL,并且由于我自动生成代码,因此可以很容易地使用另一种机制来让我们说MySQL数据源。由于不支持LINQ to SQL,因此您必须手动编写数据访问代码,但使用OO模型的客户端代码将以任何方式更改。

+0

当然,如果我必须实现一个MySQL存储库提供者,我将自己编写数据访问代码,对此没有任何问题。然而,对于这个使用LINQ生成的实体不会尴尬吗? – 2008-10-23 14:45:14

+0

我以前使用过DataSet,这是一个很好的解决方案。这可能不是最优雅的方式,但它肯定是有效的。 – Albert 2008-10-23 18:01:03

1

您的实体类可以实现将在“接口”程序集中声明的IProduct,IUser,IOrder等接口吗?这样IRepository接口只引用业务对象接口(即返回IProduct的集合等),并且“接口”组合件与其他实现特定的组件分离。

2

您不必使用LINQ to SQL生成的代码,您可以用必要的ColumnAttributes或使用外部XML映射文件来修饰自己的类。

5

您可以创建一个外部XML文件映射数据库中任一类别:

<?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> 

然后将XML传递给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; 
    } 
    } 
2

最简单的方法是将您的实体与datacontext分离开来:加载所需的实体,将其从DataContext中分离出来,然后使用它,然后使用Attach()将其与DataContext耦合以进行保存。

令人遗憾的是,LINQ没有办法将实体从数据上下文中分离出来,但是你可以克隆它们,这很好地工作。简单的方法是这样的:

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

我与WCF

1类似的东西在您的DBML,设置你的序列化模式为单向

2设置你的表中的所有列UpdateCheck的=假

3撰写您的服务类似如下:

 
    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这个位置添加一个服务引用