c# – 实体框架中的LINQ to SQL Generic Repository等效项

我正在为我的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.

点赞