我正在为我的ORM从LINQ转换为SQL到Entity Framework,我正在更新我的存储库.所有这些都是完成的,除了通用的.我似乎无法弄清楚如何将我的Select方法从现在转换为适用于EF的方法.这是当前的代码:
public T Select(int Id)
{
MetaDataMember PrimaryKey = this.DataContext.Mapping.GetTable(typeof(T)).RowType.DataMembers.SingleOrDefault(
d =>
(d.IsPrimaryKey));
ParameterExpression Param = Expression.Parameter(typeof(T), "e");
var Query = Expression.Lambda<Func<T, bool>>(Expression.Equal(Expression.Property(Param, PrimaryKey.Name), Expression.Constant(Id)), new ParameterExpression[] { Param });
return this.DataContext.GetTable<T>().Single(Query);
}
我没有写这个,我从一个人的博客中复制了它,到目前为止它对我有用.我真的不知道它做了什么,模糊的想法,但我无法将其翻译成EF.
所以,我来这里是为了请求你们的优秀女士们或先生们.如果可能的话,我会喜欢它,如果知道EF的人可以转换该声明.如果有替代代码来完成同样的事情,我会对此持开放态度.
最佳答案 如果我正确理解该方法,它将根据主键返回任何类型T的单个记录.
我们还有一个通用存储库,但界面如下所示:
public interface IRepository<T> where T : class
{
void Add(T entity);
void Remove(T entity);
void Attach(T entity);
IQueryable<T> Find();
}
我们的通用存储库实现:
public class GenericRepository<T> : IRepository<T> where T : class
{
public IQueryable<T> Find()
{
return _ctx.GetEntitySet<T>(); // EF plularization/reflection smarts
}
}
所以要获得“Post”的等效单条记录:
var postId = 1;
IRepository<Post> repository = new GenericRepository<Post>(); // done by DI in reality
repository
.Find()
.SingleOrDefault(x => x.PostId == postId); // explicit predicate to grab record
这与原始代码有很大不同 – 因为调用代码指定了主键是什么(或者是识别唯一记录的方式).
说实话,尝试基于常量主键值动态获取唯一记录是非常疯狂的 – 如果它是复合键怎么办?我看不出代码是如何工作的.
很高兴看到其他答案,但我会保持简单.
如果你想让代码基于T获取实体集,我可以分享 – 但它非常简单.
如果您想要一个方法来获取单个记录,请让调用代码提供谓词/键:
public T FindSingle(Expression<Func<T,bool>> predicate)
{
return _ctx.GetEntitySet<T>.SingleOrDefault(predicate);
}
然后,如果例如“Post”具有“PostName”和“PostType”的复合键:
var singlePost = repository.FindSingle(post => post.PostName == "Foo" && post.PostType == "Question");
在您的示例中,您的存储库正在指示您的模型,使每个实体都有一个列主键.
您的存储库应该有助于您的模型,而不是定义它.
编辑 – GetEntitySet的代码< T>,根据要求
public IObjectSet<T> GetEntitySet<T>() where T : class
{
var entityName = _plularizer.Pluralize(typeof(T).Name);
string entitySetName = string.Format("{0}.{1}", EntityContainerName, entityName);
return CreateObjectSet<T>(entitySetName );
}
非常简单,而且非常安全,因为_plularizer的类型为System.Data.Entity.Design.PluralizationService,它与EF用于创建默认实体集名称的模块相同.
EntityContainerName是实体的容器名称.
您的_plularizer实例应该是静态的,并且使用完全锁定的单例保持线程安全.
HTH.