您的位置:首页 > 其它

Entity Fr“.NET技术”amework 4.1 Code First 学习之路(二)

2011-10-13 19:27 531 查看
  写系列的上一篇已经是很久之前的事儿了= =在此期间,EF 4.1的RTW都已经出来了,NH 3.2的Alpha已经2了。。。其实不是我懒,工作中也在一直使用EF 4.1。主要是上次承诺过的一个Update功能搞不定= =

  总之这一次的目标是:

实现一个完整的IRepository(添加增删改能力)

领域对象的继承

事物

  首先来看IRepository

  我的接口如下:

[code]

[code]public interface IRepository<TEntity>
where TEntity : IEntity
{
IEnumerable<TEntity> FindAll();
TEntity FindById(int id);
void Add(TEntity entity);
void Delete(TEntity entity);
void Update(TEntity entity);
}

[/code]
应该算是一个最基本的仓储接口了。

  其中前几个接口都是很好实现的,上次提及的DbSet对象提供了相应的接口,直接调用即可,代码是类似这样的。

[code]public class BlogController : Controller
{
BlogContext db = new BlogContext();

//...

[HttpPost]
public ActionResult Edit(int id, Blog blog)
{
try
{
db.Entry(blog).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}

[/code]
很明显,在执行Edit这个Action之前,DbSet没有加载过,因为MVC帮我们保证了DbContext实例是request结束就被销毁的。

  也就是说,结论是使用这种Update实现方式对context的生命周期是有要求的.当然我的例子中context的生命周期也是per-request的所以没关系。

  那么如果我们想使用其他的context生命周期管理方式呢?比如希望整个application只有一个context实例?

  让我们来给出另一种实现

  回过头来想一想在实现Update这个方法的时候我们最初遇到的问题:entity不是从context中加载的而是直接new出来的。

  那么我们手动的来加载一次就好了么,代码类似于这样:

[code]public void上海企业网站制作or: #000000;"> Update(TEntity entity)
{
var entry = m_dbContext.Entry(entity);
if (entry.State == EntityState.Detached)
{
var entityToUpdate = FindById(entity.Id);
EmitMapper.ObjectMapperManager.DefaultInstance.GetMapper<TEntity, TEntity>().Map(entity, entityToUpdate);
}
m_dbContext.SaveChanges();
}

[/code]
当然这个实现也有不好的地方例如说当domain里有一些跟ORM没关系的property时也会被EmitMapper改写掉。

  下一个议题是领域对象的继承

  让领域对象实现继承的好处是不言而喻的,可以使用到多态等OO带来的好处。相对的就对ORM提出了更高的要求。

  我们知道映射对象树到数据库有三种经典的实现方式:Table Per Type、Table Per Hierarchy和Table Per Concrete class,这次我们来实践最简单的一种:Table Per Hierarchy。

  回想我们上一次的类:

[code]public class Hero : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
//public bool IsSuperHero { get; set; }
public virtual Race Race { get; set; }
}
public class SuperHero : Hero
{
}

[/code]
在EF Code First中这种单表继承的映射关系是这样来写的:

Map<Hero>(hero => hero.Requires(ColumnNameMappingStrategy.Value.To("IsSuperHero")).HasValue(false)).ToTable(tableNameMappingStrategy.To("Hero"));
Map<SuperHero>(hero => hero.Requires(ColumnNameMappingStrategy.Value.To("IsSuperHero")).HasValue(true)).ToTable(tableNameMappingStrategy.To("Hero"));


  另外两种方式的实现也不复杂,可以参考这里。这个实例还是CTP5的API,跟4.1最终版有些区别不过应该影响不大。

  今天最后的议题是事物

  可以用TransactionScope来管理,虽然看起来有些浪费,毕竟例子中不涉及Transaction传播,连DbContext都只有一个实例。代码如下:

[HttpPost]
public ActionResult Edit(TEntity entity)
{
try
{
using (var scope = new TransactionScope())
{
ModelRepository.Update(entity);
scope.Complete();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}


  Spring实际上也可以用AOP的方式管理TransactionScope。不过我倾向于手动管理Transaction。

  代码下载

  本次的代码请参考这个changeset

  今天就到这里-v-
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: