假设我的域模型与物理模型的对应关系为1:1。也:
目标:创建域模型类(POCO)和相应的存储库。工具 - VS2010,EF4.1
最明显的方法是从DB生成EF模型,然后在其上运行T4 POCO Generator。输出是一组POCO类。
//POCO classes
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime LastModified { get; set; }
...
}
public class User
{
public int Id { get; set; }
public string FirtsName { get; set; }
public DateTime LastModified { get; set; }
...
}
到目前为止一直很好但我们在实现存储库时遇到了一些代码重复。两者都在接口定义级别:
public interface ICountryRepository
{
IEnumerable<Country> FindAll();
Country FindById(int id);
void Add(Country country);
void Delete(Country country);
}
//Here the ONLY difference is the type of the entity
public interface IUserRepository
{
IEnumerable<User> FindAll();
User FindById(int id);
void Add(User user);
void Delete(User user);
}
在实施层面:
class CountryRepository : ICountryRepository
{
IEnumerable<Country> FindAll()
{
//implementation
}
Country FindById(int id)
{
//find by id logic
}
void Add(Country country)
{
//logic
}
void Delete(Country country)
{
//logic
}
}
class UserRepository : IUserRepository
{
IEnumerable<User> FindAll()
{
//the only difference in the implementation
//is the type of returned entity
}
User FindById(int id)
{
//the only difference in the implementation
//is the type of returned entity
}
void Add(User user)
{
//the only difference in the implementation
//is the type of returned entity
}
void Delete(User user)
{
//the only difference in the implementation
//is the type of returned entity
}
}
考虑到上面的大多数代码可以更一般地编写,我们也可以采取以下方法。
创建POCO对象层次结构:
public class EntityBase
{
public int Id { get; set; }
}
public class TrackableEntity : EntityBase
{
public DateTime LastChanged { get; set; }
}
public class LocalizedEntity : TrackableEntity
{
public int ResourceId { get; set; }
}
public class Country : LocalizedEntity
{
}
然后使用基础实现的存储库层次结构:
public interface IRepository<TEntity> where TEntity : EntityBase
{
IEnumerable<TEntity> FindAll();
TEntity FindById(int id);
void Add(TEntity entity);
void Delete(TEntity entity);
}
public interface ILocalizedRepository<TEntity> : IRepository<TEntity> where TEntity : LocalizedEntity
{
IEnumerable<TEntity> FindByCultureIso2(string cultureIso2);
}
public interface ICountryRepository : ILocalizedRepository<Country>
{
}
internal class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : EntityBase
{
private readonly IObjectSet<TEntity> _objectSet;
public RepositoryBase(ObjectContext database)
{
_objectSet = database.CreateObjectSet<TEntity>();
}
protected virtual IQueryable<TEntity> All()
{
return _objectSet;
}
public virtual IEnumerable<TEntity> FindAll()
{
return All().ToList();
}
public virtual TEntity FindById(int id)
{
return All().Where(entity => entity.Id == id).SingleOrDefault();
}
public virtual void Add(TEntity entity)
{
_objectSet.AddObject(entity);
}
public virtual void Delete(TEntity entity)
{
_objectSet.DeleteObject(entity);
}
}
internal class LocalizedRepositoryBase<TEntity> : RepositoryBase<TEntity>, ILocalizedRepository<TEntity> where TEntity : LocalizedEntity
{
public LocalizedRepositoryBase(ObjectContext database) : base(database)
{
}
protected override IQueryable<TEntity> All()
{
return (base.All() as ObjectSet<TEntity>).Include("Resource.LocalizedResources.Culture");
}
public IEnumerable<TEntity> FindByCultureIso2(string cultureIso2)
{
IEnumerable<TEntity> entities = All().Where(...);
return entities.ToList();
}
}
internal class CountryRepository : LocalizedRepositoryBase<Country>, ICountryRepository
{
public CountryRepository(ObjectContext database) : base(database)
{
}
}
后一种方法的令人信服的优点是代码更加结构化,可以避免代码重复。
但这种情况几乎不适合T4代码,这为大量的手工工作开辟了道路。
如果您让我知道您在考虑以下事项,我将不胜感激:
答案 0 :(得分:2)
如果您最关心的是手动实现POCO,请使用接口来定义共享功能而不是基类:
public interface IEntityBase
{
int Id { get; set; }
}
public interface ITrackableEntity : IEntityBase
{
DateTime LastChanged { get; set; }
}
public interface ILocalizedEntity : ITrackableEntity
{
int ResourceId { get; set; }
}
现在您不需要手动实施POCO。 Generator会为您创建实体,您只需要为每个实体定义部分部分,以定义它实现的接口。
public partial class Country : ILocalizedEntity
{ }
如果您对T4修改感到满意,您甚至可以直接将界面分辨率添加到T4,您无需定义这些部分部分。
答案 1 :(得分:0)
如果你正在生成代码,可以复制,只是不要触摸生成的代码,你就可以了。