我正在使用”存根技术“ 至 更新 我的poco(用于独立的上下文,ASP.NET MVC)。

这是我当前控制器中的代码(可行):

[HttpPost]
public ActionResult Edit(Review review)
{
   Review originalReview = _userContentService.FindById(review.PostId) as Review;
   var ctx = _unitOfWork as MySqlServerObjectContext;
   ctx.ApplyCurrentValues("MyEntities.Posts", review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

如您所见,到处都有代码气味。 :)

几点:

  1. 我使用依赖注入(基于接口)的所有内容
  2. 我使用工作模式单位来抽象objectContext并在多个存储库之间提供持久性
  3. 目前是我的 iunitofwork 接口只有1种方法: void Commit();
  4. 控制器有 IUserContentServiceIUnitOfWork 注射di
  5. IUserContentService 呼叫 Find 在存储库中,使用 ObjectContext.

这是我不喜欢上述代码的两件事:

  1. 我不想施放 iunitofwork 作为 MySqlServerObjectContext.
  2. 我不希望控制器必须关心 ApplyCurrentValues

我基本上希望我的代码看起来像这样:

[HttpPost]
public ActionResult Edit(Review review)
{
   _userContentService.Update(review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

有什么想法,我该怎么做? (或类似的东西)。

我已经有聪明的人可以根据类型(仿制药的组合,复数化)来制定实体设置名称,因此请不要为此担心太多。

我想知道最好的地方 ApplyCurrentValues?将其放在 IUnitOfWork 接口,因为这是一个持久性(EF)的问题。出于同样的原因,它不属于服务。如果我把它放在我的 MySqlServerObjectContext 班级(有道理),我会从哪里称呼,因为没有什么可以直接可以访问此类 - 当某物请求时,它会通过DI注入 IUnitOfWork.

有什么想法吗?

编辑

我在下面使用存根技术有一个解决方案,但是问题是,如果我已提前检索了要更新的实体,则会引发异常,并说明已经存在该密钥的实体。

这是有道理的,尽管我不确定如何解决这个问题?

我是否需要“检查实体是否已经连接,如果没有附加,请附加?”

那里的EF4专家可以提供帮助吗?

编辑

没关系 - 找到解决方案,请参见下面的答案。

有帮助吗?

解决方案

弄清楚了 - 这并不容易,所以我会尽力解释我能做到的。 (对于那些关心的人)

控制器相关代码:

// _userContentService is IUserContentService
_userContentService.Update(review);

因此,我的控制器调用了一种称为的方法 UpdateIUserContentService, ,穿过强大的 Review 目的。

用户内容服务相关代码

public void Update(Post post)
{
   // _userContentRepository is IPostRepository
   _userContentRepository.UpdateModel(post);
}

因此,我的服务调用了一种称为的方法 UpdateModelIPostRepository, ,穿过强大的 Review 目的。

现在,这是棘手的部分。

我实际上有 没有特定的存储库. 。我有一个 通用存储库GenericRepository<T> : IRepository<T>, ,哪个处理 所有不同的存储库。

因此,当某事请求 IPostRepository (我的服务正在做),di会给它一个 GenericRepository<Post>.

但是现在,我给它一个 PostRepository:

public class PostRepository : GenericRepository<Post>, IPostRepository
{
   public void UpdateModel(Post post)
   {
      var originalPost = CurrentEntitySet.SingleOrDefault(p => p.PostId == post.PostId);
      Context.ApplyCurrentValues(GetEntityName<Post>(), post);
   }
}

而且因为班级 衍生通用物, ,它继承了所有核心存储库逻辑(查找,添加等)。

起初,我试图把那个 UpdateModel 代码 通用物 类本身(然后我不需要这个特定的存储库),但是问题是检索现有实体的逻辑是基于特定实体密钥, GenericRepository<T> 不知道。

但最终结果是 缝合 隐藏在数据层深处的深处,我最终得到了一个非常干净的控制器。

编辑

这种“存根技术”也有效:

public void UpdateModel(Post post)
{
   var stub = new Review {PostId = post.PostId};
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>(), post);
}

但是问题是因为 邮政 是抽象的,我不能实例化,因此必须检查帖子的类型并为 每一个 派生类型。并不是真正的选择。

编辑2(上次)

好的,获得了与抽象类合作的“存根技术”,因此现在解决了并发问题。

我在我的 UpdateModel 方法和特殊 新()约束.

执行:

public void UpdateModel<T>(T post) where T : Post, new()
{
   var stub = new T { PostId = post.PostId };
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>, post);
}

界面:

void UpdateModel<T>(T post) where T : Post, new();

这样可以防止我不得不手动弄清楚T的类型,防止并发问题,并防止额外的DB旅行。

很开心。

编辑3(我以为上次是最后一次)

上面的“存根技术”有效,但是如果我事先检索对象,则会引发一个例外,说明具有该密钥的实体已经存在于OSM中。

谁能建议如何处理?

编辑4(好的 - 就是这样!)

我找到了解决方案,这要归功于这个答案: 是否可以检查实体框架中的数据上下文是否已经连接到对象?

我曾尝试使用以下代码“检查实体是否已连接”:

ObjectStateEntry entry;
CurrentContext.ObjectStateManager.TryGetObjectStateEntry(entity, out entry);

但是它总是返回 无效的, ,即使在探索OSM的过程中,我也可以看到我的实体使用相同的钥匙。

但是此代码有效:

CurrentContext.ObjectStateManager.TryGetObjectStateEntry(CurrentContext.CreateEntityKey(CurrentContext.GetEntityName<T>(), entity), out entry)

也许是因为我正在使用Pure Poco,所以OSM难以弄清楚实体密钥,谁知道。

哦,还有我添加的另一件事 - 这样我就不必为每个实体添加一个特定的存储库,我创建了一个称为“EntityKey”(公共财产属性)。

所有POCO都必须拥有1个带有该属性的公共财产,否则我在存储库模块中抛出了一个例外。

因此,我的通用存储库然后寻找此属性,以创建/设置存根。

是的 - 它使用反射,但它是巧妙的反射(基于属性),我已经在使用反射来对T。

无论如何,问题解决了 - 现在一切正常!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top