实体类与 LINQ to SQL 提供程序解耦,以实现存储库模式。 如何?

发布于 2024-07-07 09:09:11 字数 557 浏览 10 评论 0原文

我查看了存储库模式,并认识到我过去使用的一些想法让我感觉良好。

但是现在我想编写一个使用此模式的应用程序但我希望从存储库提供程序中将实体类解耦

我将创建几个程序集:

  1. 一个“接口”程序集,它将托管公共接口,包括 IRepository 接口;
  2. 一个“实体”程序集,它将托管产品、用户、订单等实体类。 该程序集将由“Interfaces”程序集引用,因为某些方法将返回此类类型或它们的数组。 它还将被主应用程序程序集(例如 Web 应用程序)
  3. 一个或多个存储库提供程序程序集引用。 每个都包含(至少)一个实现 IRepository 接口的类,并且它将与特定的数据存储一起使用。 数据存储可以包括 SQL Server、Oracle 服务器、MySQL、XML 文件、Web/WCF 服务等。

研究 LINQ to SQL 从实现所有内容所需的时间来看似乎非常高效,直到我发现生成的类和 CustomDataContext 类之间的深层依赖关系。

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

I have looked over the Repository pattern and I recognized some ideas that I was using in the past which made me feel well.

However now I would like to write an application that would use this pattern BUT I WOULD LIKE TO HAVE THE ENTITY CLASSES DECOUPLED from the repository provider.

I would create several assemblies :

  1. an "Interfaces" assembly which would host common interfaces including the IRepository interface
  2. an "Entities" assembly which would host the entity classes such as Product, User, Order and so on. This assembly would be referenced by the "Interfaces" assembly since some methods would return such types or arrays of them. Also it would be referenced by the main application assembly (such as the Web Application)
  3. one or more Repository provider assembly/assemblies. Each would include (at least) a class that implements the IRepository interface and it would work with a certain Data Store. Data stores could include an SQL Server, an Oracle server, MySQL, XML files, Web / WCF services and so on.

Studying LINQ to SQL which looks very productive in terms of time taken to implement all seems well until I discover the deep dependency between the generated classes and the CustomDataContext class.

How can I use LINQ to SQL in such a scenario?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

听你说爱我 2024-07-14 09:09:11

我不知道这是否正是您想要的,但您可能想看看 Rob Conery 的 MVC Storefront 代码。 他使用带有 linq 提供程序的存储库模式的变体。 他将 LINQ to Sql 对象映射到域对象,然后将域对象从存储库提供程序返回到服务层,该服务层包装提供程序,允许他在返回的数据到达业务层之前对返回的数据进行一些逻辑处理。

MVC 店面网络广播
代码

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

在这种情况下,您将拥有:
ProductService,它采用 IProductRepository。 它调用 IProductRepository 上的方法来取回您的 DTO。 然后,它将 DTO 映射到实际业务对象,并将它们返回给调用代码。

I don't know if this is exactly what you want, but you may want to take a look at Rob Conery's MVC Storefront code. He uses a variant of the repository pattern with a linq provider. He maps the LINQ to Sql objects to domain objects and then returns the domain objects from the repository provider to a service layer which wraps the provider allowing him to work some logic on the data returned before it hits the business layer.

MVC Storefront Webcasts
Code

To me it sounds like you want the providers to return DTOs and then you want to map the DTOs to the domain objects in the repository/service layer. If this is the case you could map your LINQ to SQL provider to the DTOs, have it return them, then map the DTOs to domain objects in the repository/service layer. This should work just fine, but it may become tedious as you now would have 2 mapping layers.

In this case you would have:
ProductService, which takes an IProductRepository. It evokes methods on the IProductRepository to get back your DTOs. It then maps the DTOs to the real business objects and returns them to the calling code.

会发光的星星闪亮亮i 2024-07-14 09:09:11

您可以创建将数据库映射到任何类的外部 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;
     }
  }

You can create an external XML file mapping the database to any class:

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

And then pass the XML to a DataContext class:

 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;
     }
  }
浮萍、无处依 2024-07-14 09:09:11

我在这里找到了一篇很棒的博客文章(有很多好的代码):http://iridescent.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx

I found a fantastic blog post (with lots of good code) about this here: http://iridescence.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx

油饼 2024-07-14 09:09:11

我认为您需要 POCO(普通旧 CLR 对象)支持。 LINQ to SQL 有一个名为 Close2Poco 的适配器。

但我建议切换到实体框架,目前他们还有一个 POCO 适配器 ,但在 v2 预计将得到开箱即用的支持

I think you want POCO (Plain Old CLR Objects) support. LINQ to SQL has a adapter called Close2Poco.

But I would advise making the switch to Entity Framework, at the moment they also have a POCO adapter, but in v2 its expected to be supported out of the box.

橙幽之幻 2024-07-14 09:09:11

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

You don't have to use the LINQ to SQL generated code, you can decorate your own classes with the necessary ColumnAttributes or use an external XML mapping file.

一指流沙 2024-07-14 09:09:11

最简单的方法是将实体与数据上下文解耦:加载所需的实体,将其与 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);
  }
}

The simplest way would be to decouple your entities from the datacontext: load the needed entity, decouple it from the DataContext, use it however you like, later use Attach() to couple it with a DataContext for saving.

Sadly LINQ has no method to decouple entities from a datacontext, but you can just clone them, that works nicely. Simplest way would be something like this:

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);
  }
}
貪欢 2024-07-14 09:09:11

我对 WCF 做了类似的操作

1 在您的 DBML 上,将序列化模式设置为单向

2 将表上的所有列设置为 UpdateCheck=false

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 添加服务参考

I did something similar with WCF

1 On your DBML, set you Serialization mode to Unidirectional

2 Set ALL columns on your tables to UpdateCheck=false

3 Write your service something like the following:

   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 Add a service reference

我不吻晚风 2024-07-14 09:09:11

场景并不完全相同,但我正在努力创建一个基于 XML 文件的自定义工具,该工具将生成 OO 模型。 我的方法是在后台使用 LINQ to SQL,并且由于我自动生成代码,因此很容易使用另一种机制(例如 MySQL 数据源)。 由于 LINQ to SQL 不支持它,因此您必须手动编写数据访问代码,但使用 OO 模型的客户端代码将会发生任何变化。

Not exactly the same scenario, but I'm working to create a custom tool that based on a XML file will generate an OO model. My approach is to use LINQ to SQL behind the scene and since I'm generating the code automatically it would be easy to use another mechanism for let's say MySQL data source. Since it's not supported by LINQ to SQL you will have to write the data access code manually, but the client code that will use the OO model will change in any way.

朮生 2024-07-14 09:09:11

您的实体类能否实现在“Interfaces”程序集中声明的 IProduct、IUser、IOrder 等接口? 这样,IRepository 接口仅引用业务对象接口(即,返回 IProduct 等的集合),并且“Interfaces”程序集与其他特定于实现的程序集分离。

Could your Entity classes implement IProduct, IUser, IOrder etc. interfaces that would be declared in your "Interfaces" assembly? This way the IRepository interface references only the business object interfaces (i.e., returns collections of IProduct etc.) and the "Interfaces" assembly is decoupled from your other implementation-specific assemblies.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文