使用存储库模式实现 WCF 数据服务

发布于 2024-11-25 04:51:48 字数 2633 浏览 3 评论 0原文

我们在 ASP.NET MVC 3 应用程序中使用存储库模式。这意味着,尽管我们使用 EF 4.1 Code First 来访问后端中的数据,但所有 MVC 控制器都是通过通用存储库类而不是直接通过 DbContext 子类来执行此操作。

简化的代码片段:

public class MyEntityContext : DbContext, IMyEntityContext
{
    public IDbSet MyEntities { get; set; }
    ...
}

public class MyEntityRepository : IMyEntityRepository
{
    private IMyEntityContext _context;

    public IQueryable<MyEntity> MyEntities
    {
        return _context.MyEntities;
    }
    ...
}

public class MyEntityController : Controller
{
    private MyEntityRepository _repository;
    ...
}

我们为每个依赖项使用接口和依赖项注入。效果很好。看起来不错,不是吗?但现在需要注意的是:

我们还提供 WCF 数据服务(支持 Code First 的 CTP)来访问实体。我们也想在该服务中使用存储库。但这似乎很棘手。直接使用 MyEntityContext 时,服务如下所示:

public class MyEntityService : DataService<MyEntityContext>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("MyEntities", EntitySetRights.All);
    }
}

但是当我尝试用存储库替换 MyEntityContext 时,存在两个问题:

  1. 为泛型 < 指定的类型code>DataService<..> 需要是一个具有默认构造函数的类,这打破了漂亮的契约设计和依赖注入设计。
  2. 甚至看起来提供的类型必须是 DbContext 类:我尝试并使用 MyEntityRepository 来代替,但失败了(查看详细信息)。

我似乎迷失了......有人能带我回到正确的轨道吗?


详细信息:

我的第一次尝试是:

public class MyEntityService : DataService<MyEntityRepository>
{
    ...

但是,在调用该服务时,它失败并显示以下错误消息:

服务器在处理请求时遇到错误。异常消息是“在数据上下文类型“MyEntityRepository”上,有一个顶级 IQueryable 属性“MyEntities”,其元素类型不是实体类型。确保 IQueryable 属性属于实体类型,或者在数据上下文类型上指定 IgnoreProperties 属性以忽略此属性。'。

我尝试了以下步骤来修复此问题,但没有消除此错误消息:

  • [DataServiceKey("MyEntityId")] 添加到 MyEntity,其中 MyEntityId 是实体的正确关键属性。
  • Repository.MyEntities 的类型替换为 IDbSet 而不是 IQueryable

顺便说一句:以下帖子重复:

We are using the repository pattern in our ASP.NET MVC 3 application. This means that, although we use EF 4.1 Code First to access the data in the backend, all MVC controllers do that via a generic repository class rather than directly over the DbContext subclass.

Simplified code snippet:

public class MyEntityContext : DbContext, IMyEntityContext
{
    public IDbSet MyEntities { get; set; }
    ...
}

public class MyEntityRepository : IMyEntityRepository
{
    private IMyEntityContext _context;

    public IQueryable<MyEntity> MyEntities
    {
        return _context.MyEntities;
    }
    ...
}

public class MyEntityController : Controller
{
    private MyEntityRepository _repository;
    ...
}

We use interfaces and dependency injection for every dependency. It works fine. Looks nice, doesn't it? But now for the caveat:

We also provide a WCF Data Service (CTP supporting Code First) to access the entities. We want to use the repository in that service, too. But this seems tricky. When using the MyEntityContext directly, the service looks like this:

public class MyEntityService : DataService<MyEntityContext>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("MyEntities", EntitySetRights.All);
    }
}

But when I try to replace the MyEntityContext by the repository, there are two issues:

  1. The type specified for the generic DataService<..> needs to be a class with a default constructor, which breaks the pretty design-by-contract and dependency injection design.
  2. It even seems that the type provided has to be a DbContext class: I tried and used the MyEntityRepository instead, but failed (see details).

I seem lost... Can anyone bring me back on the proper track?


Details:

My first go was:

public class MyEntityService : DataService<MyEntityRepository>
{
    ...

However, when calling the service, it fails with the following error message:

The server encountered an error processing the request. The exception message is 'On data context type 'MyEntityRepository', there is a top IQueryable property 'MyEntities' whose element type is not an entity type. Make sure that the IQueryable property is of entity type or specify the IgnoreProperties attribute on the data context type to ignore this property.'.

I tried the following steps to fix this, but did not get rid of this error message:

  • Adding a [DataServiceKey("MyEntityId")] to MyEntity, where MyEntityId is the correct key property of the entity.
  • Replacing the type of Repository.MyEntities by IDbSet instead of IQueryable.

BTW: The following posts are not duplicates:

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

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

发布评论

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

评论(2

雨夜星沙 2024-12-02 04:51:48

为什么要使用存储库?你有上下文,所以使用它。不要仅仅因为想要使用模式就创建洋葱架构。 WCF 数据服务本身已经可以处理您需要的一切。不抱歉,它有时提供更多(例如拦截器)。

通过使用自定义存储库,您将移至反射提供程序数据源。如果您还计划通过 WCF 数据服务修改实体,这也会针对您的存储库,因为反射提供程序是只读的,除非它也实现了 IUpdateable。另请检查反射提供程序的规则

顺便提一句。 .NET 4 中的 WCF 数据服务不直接支持 DbContext(该支持仅在即将推出的版本的 CTP 中),但您可以解决方法。该链接适用于旧 CTP。在当前版本中没有 UnderlyingContext 属性,但您可以使用 IObjectContextAdapter 来获取 ObjectContext

正如您在最后一个提供给服务的链接类型中看到的那样,不需要具有默认构造函数 - 这取决于您在创建数据源时使用的构造函数。如果您需要依赖项注入,您可能必须检查如何直接注入到服务本身的方式(例如 此处 适用于 Unity 和普通 WCF)并在 CreateDataSource 中使用注入的数据。

Why do you want to use repository? You have context so use it. Don't create onion architecture just because you want to use pattern. WCF data service already handles everything you need itself. No sorry, it sometimes offers even more (for example interceptors).

By using custom repository you are moving to reflection provider data source. If you also plan to modify your entities through WCF data service that is also against your repository because reflection provider is read only unless it also implements IUpdateable. Check also rules for reflection provider.

Btw. WCF Data Services in .NET 4 doesn't support DbContext directly (that support is only in CTPs of upcoming version) but you there is workaround for that. The link is for old CTP. In current version there is not UnderlyingContext property but you can use IObjectContextAdapter to get ObjectContext.

As you can also see in last link type provided to the service doesn't need to have default constructor - it is up to you what constructor you use when creating data source. If you need dependency injection you will probably have to check the way how to inject directly to the service itself (for example here for Unity and plain WCF) and use injected data in CreateDataSource.

你不是我要的菜∠ 2024-12-02 04:51:48

以下是如何使用您正在使用的任何模式(甚至根本没有模式)创建 WCF 数据服务。

OData 入门第 2 部分:从任何数据源构建 OData 服务

确保您的实体、poco、模型或任何内容具有 public int ID 属性,或者具有由 System.Data.Services 程序集提供的此类注释System.Data.Services 命名空间:

[DataServiceKey("TheNameOfYourPrimaryKeyProperty")]

这将使其能够被 WCF 数据服务识别为实体类型。

正如其他人指出的那样,只需确保在堆栈中添加另一层是一个不错的决定。

Here's how to make a WCF Data Service with whatever pattern you're using, even none at all.

Getting Started With OData Part 2: Building an OData Services from Any Data Source

Just make sure your entity, poco, model or whatever has a property public int ID , or has this class annotation provided by the System.Data.Services assembly in the System.Data.Services namespace:

[DataServiceKey("TheNameOfYourPrimaryKeyProperty")]

This will make it recognizable as an entity type by the WCF Data Service.

As others have pointed out though, just make sure that adding yet another layer in your stack is a good decision.

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