实体框架4 - 如果把" ApplyCurrentValues​​"逻辑? [英] Entity Framework 4 - Where to put "ApplyCurrentValues" Logic?

查看:206
本文介绍了实体框架4 - 如果把" ApplyCurrentValues​​"逻辑?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了存根技术 更新我的POCO的(在分离的情况下,ASP.NET MVC使用)。

I'm using the "stub technique" to update my POCO's (used in a detached context, ASP.NET MVC).

这是在我的控制器代码我现在有(工作):

This is the code i currently have in my controller (which works):

[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..
}



正如你可以看到,有码味无处不在。 :)

As you can see, there is code smell everywhere. :)

的几点:


  1. 我使用依赖注入(接口 - 开始),基本上一切

  2. 我用工作单元模式抽象的ObjectContext和提供持久跨多个存储库

  3. 目前我的 IUnitOfWork 接口只有1个方法:无效提交();

  4. 控制器具有 IUserContentService IUnitOfWork 通过DI注入

  5. IUserContentService 通话查找在存储库,它使用的ObjectContext

  1. I use Dependency Injection (interface-based) for basically everything
  2. I use the Unit of Work pattern to abstract ObjectContext and provide persistence across multiple repositories
  3. Currently my IUnitOfWork interface has only 1 method: void Commit();
  4. Controller have IUserContentService and IUnitOfWork inject by DI
  5. IUserContentService calls Find in Repositories, which use the ObjectContext.

这是两件事情,我不与我上面的代码,如:

These are two things i don't like with my above code:


  1. 我不想投的 IUnitOfWork MySqlServerObjectContext

  2. 我不想控制器有关心 ApplyCurrentValues​​

  1. I don't want to cast the IUnitOfWork as MySqlServerObjectContext.
  2. I don't want the Controller to have to care about ApplyCurrentValues

我基本上想我的代码看起来是这样的:

I basically want my code to look like this:

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



任何想法我怎么能做到这一点? (或类似的东西)。

Any ideas how i can do that? (or something similar).

我已经有聪明才智的基础的类型(仿制药的组合,复数)制定的实体集的名称,所以不用太担心多少有关。

I already have smarts to work out the entity set name based on the type (combination of generics, pluralization), so don't worry too much about that.

我想知道哪里最好的地方,把 ApplyCurrentValues​​ ?它似乎不恰当的把它放在 IUnitOfWork 接口,因为这是一个持久性(EF)的关注。出于同样的原因,它不在服务归属。如果我把它放在我的 MySqlServerObjectContext 类(有意义),在那里,我会称之为而来,如无直接访问这个类 - 它是通过DI什么请求时注入 IUnitOfWork

But i'm wondering where the best place to put ApplyCurrentValues is? It doesn't seem appropriate to put it in the IUnitOfWork interface, as this is a persistence (EF) concern. For the same reason it doesn't belong in the Service. If i put it in my MySqlServerObjectContext class (makes sense), where would i call this from, as nothing directly has access to this class - it is injected via DI when something requests IUnitOfWork.

有什么想法?

修改

我有以下使用存根技术的解决方案,但问题是,如果我有取回了我事先更新的实体,它抛出一个异常,说明与该键已经存在的实体。

I have a solution below using the stub technique, but the problem is if i had retrieved the entity i am updating beforehand, it throws an exception, stating an entity with that key already exists.

这是有道理的,虽然我不知道如何解决这个问题?

Which makes sense, although i'm not sure how can resolve this?

我是否需要检查实体已连接,如果没有,重视吗?

Do i need to "check if the entity is already attached, if not, attach it?"

任何EF4专家在那里可以帮助?

Can any EF4 experts out there help?

修改

没关系 - 找到了解决办法,请参见下面的回答

Nevermind - found the solution, see answer below.

推荐答案

想通了 - 是不容易的,所以我会尽力解释尽我所能。 (对于那些谁在乎)

Figured it out - wasn't easy, so i'll try to explain best i can. (for those who care)

控制器相关代码:

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



所以,我的控制器调用一个名为更新方法 IUserContentService ,通过强类型审核通过对象。

So, my controller calls a method called Update on IUserContentService, passing through the strongly-typed Review object.

用户内容服务相关的代码

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



所以,我的服务调用一个名为的UpdateModel <方法/ code>在 IPostRepository ,通过强类型审核对象。

现在,这里是棘手的部分。

Now, here is the tricky part.

其实,我的没有具体的资料库。我有一个的通用库的名为 GenericRepository< T> :IRepository< T> ,它处理的所有不同的存储库

I actually have no specific Repositories. I have a generic repository called GenericRepository<T> : IRepository<T>, which handles all the different repositories.

所以,当一些请求 IPostRepository (其中我的服务是做),DI想给它一个 GenericRepository<邮政方式>

So when something requests a IPostRepository (which my service was doing), DI would give it a 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);
   }
}

和因为类的导出 GenericRepository ,它继承了所有的核心库逻辑(查找,添加,等等)。

And because the class derives from GenericRepository, it inherits all the core repository logic (Find, Add, etc).

起初,我试图把那个< STRONG>的UpdateModel 在代码中的 GenericRepository 类本身(然后我就不会需要这个特定的存储库),但问题是检索现有实体的逻辑是基于特定实体键,其中 GenericRepository< T> 不会知道

At first, i tried to put that UpdateModel code in the GenericRepository class itself (and then i wouldn't have needed this specific repository), but the problem is the logic to retrieve the existing entity is based on a specific entity key, which the GenericRepository<T> would not know about.

但最终的结果是拼接的在数据层的深处内心深处隐藏的,我结束了一个非常干净的控制器。

But the end result is the stitching is hidden deep down in the depths of the data layer, and i end up with a really clean Controller.

修改

这存根技术也可以工作:

This "stub technique" also works:

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



但问题是,因为发表是抽象的,我不能实例化,因此将不得不检查后的类型和创造的每一个的派生类型存根。不是一个真正的选择。

But the problem is because Post is abstract, i cannot instantiate and therefore would have to check the type of Post and create stubs for every single derived type. Not really an option.

编辑2(最后一次)

好吧,拿到存根技术抽象类的工作,所以现在的并发问题就解决了​​。

Okay, got the "stub technique" working with abstract classes, so now the concurrency issue is solved.

我添加了一个泛型类型参数来我的的UpdateModel 方法和特殊的 new()约束

I added a generic type parameter to my UpdateModel method, and the special new() constraint.

实施

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的类型,防止并发问题,也可防止额外的旅行到数据库。

This prevents me from having to figure out the type of T manually, prevents concurrency issues and also prevents an extra trip to the DB.

漂亮时髦。

修改3(我想最后一次是最后一次)

上面的存根技术的作品,但如果我事先检索的对象,它抛出一个异常,说明与该键的实体已经存在于OSM。

The above "stub technique" works, but if i retrieve the object beforehand, it throws an exception stating an entity with that key already exists in the OSM.

谁能告诉我如何处理?

修改4( OK! - 这就是它)

我找到了解决方案,这要归功于该SO回答:的是否可以检查是否有对象已经附加到实体框架数据上下文

I found the solution, thanks to this SO answer: Is is possible to check if an object is already attached to a data context in Entity Framework?

我曾试图检查实体连接使用下面的代码:

I had tried to "check if the entity is attached" using the following code:

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



但它总是返回的无效,甚至可以通过当我探索了OSM我。莫不是看我的实体使用相同的密钥

But it always returned null, even through when i explored the OSM i could see my entity there with the same key.

不过,此代码的工作:

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

也许是因为我使用的纯POCO年代,OSM遇到了麻烦搞清楚实体键,谁也不知道。

Maybe because i'm using Pure POCO's, the OSM had trouble figuring out the entity key, who knows.

呵呵及一件事我说 - 这样我就不必添加特定的资源库为每个实体,我创建了一个名为 [的EntityKey] (公共财产属性)

Oh and one other thing i added - so that i don't have to add a specific repository for each entity, i created an attribute called "[EntityKey]" (public property attribute).

所有POCO的必须有1公共财产的装饰与属性,或者我扔在我的仓库模块异常。

All POCO's must have 1 public property decorated with that attribute, or i throw an exception in my repository module.

所以,我的通用版本库,那么长相对于这个属性,以创建/设置存根

So my generic repository then looks for this property in order to create/setup the stub.

是 - 它使用反射,但它是聪明的反射(属性为基础的),我已经使用反射的从T实体集名称的plularization

Yes - it uses reflection, but it's clever reflection (attribute-based) and i'm already using reflection for plularization of entity set names from T.

总之,问题就解决了​​ - 现在所有工作正常。

Anyway, problem solved - all working fine now!

这篇关于实体框架4 - 如果把&QUOT; ApplyCurrentValues​​&QUOT;逻辑?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆