实体框架4 - 如果把" ApplyCurrentValues"逻辑? [英] Entity Framework 4 - Where to put "ApplyCurrentValues" Logic?
问题描述
我使用了的存根技术 为更新我的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. :)
的几点:
- 我使用依赖注入(接口 - 开始),基本上一切
- 我用工作单元模式抽象的ObjectContext和提供持久跨多个存储库
- 目前我的 IUnitOfWork 接口只有1个方法:
无效提交();
- 控制器具有
IUserContentService
和IUnitOfWork
通过DI注入 -
IUserContentService
通话查找
在存储库,它使用的ObjectContext
。
- I use Dependency Injection (interface-based) for basically everything
- I use the Unit of Work pattern to abstract ObjectContext and provide persistence across multiple repositories
- Currently my IUnitOfWork interface has only 1 method:
void Commit();
- Controller have
IUserContentService
andIUnitOfWork
inject by DI IUserContentService
callsFind
in Repositories, which use theObjectContext
.
这是两件事情,我不与我上面的代码,如:
These are two things i don't like with my above code:
- 我不想投的 IUnitOfWork 为
MySqlServerObjectContext
。 - 我不想控制器有关心
ApplyCurrentValues
- I don't want to cast the IUnitOfWork as
MySqlServerObjectContext
. - 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()约束 。STRONG>
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 - 如果把" ApplyCurrentValues"逻辑?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!