简体   繁体   English

实体框架中的LINQ to SQL通用存储库等效项

[英]LINQ to SQL Generic Repository equivalent in Entity Framework

I'm converting from LINQ to SQL to Entity Framework for my ORM and I'm updating my repositories. 我正在为我的ORM从LINQ转换为SQL,再转换为Entity Framework,并且正在更新存储库。 All of them are done except for the generic one. 除了通用的以外,所有这些都已完成。 I can't seem to figure out how to convert my Select method from what it is now to one that works with EF. 我似乎无法弄清楚如何将Select方法从现在的方法转换为可以与EF一起使用的方法。 Here's the current code: 这是当前代码:

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);
}

I didn't write this, I copied it from some person's blog and it's worked for me so far. 我没有写这篇文章,而是从某人的博客复制过来的,到目前为止,它对我来说是有用的。 I really don't know what it does, vague idea, but I'm not capable of translating it to EF. 我真的不知道它的作用,模棱两可的想法,但是我无法将其转换为EF。

So, I've come here to ask for the assistance of you fine ladies or gentlemen. 所以,我来这里是为了寻求各位女士或先生们的帮助。 If possible, I'd love it if someone who knows EF can convert that statement. 如果可能的话,如果知道EF的人可以转换该语句,我会喜欢的。 If there's alternative code to accomplish the same thing, I'm open to it. 如果有其他代码可以完成同一件事,那么我很乐意。

If i understand that method correctly, it returns a single record for any type T, based on a primary key. 如果我正确理解该方法,它将基于主键返回任何T类型的单个记录。

We also have a generic repository, but the interface looks like this: 我们也有一个通用的存储库,但是界面如下所示:

public interface IRepository<T> where T : class
{
   void Add(T entity);
   void Remove(T entity);
   void Attach(T entity);
   IQueryable<T> Find();
}

And our generic repository implementation: 以及我们的通用存储库实现:

public class GenericRepository<T> : IRepository<T> where T : class
{
   public IQueryable<T> Find()
   {
      return _ctx.GetEntitySet<T>(); // EF plularization/reflection smarts
   }
}

So to get the equivalent single record for a "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

That's a lot different to your original code - as the calling code is specifying what the primary key is (or a way to identity a unique record). 这与原始代码有很大不同-调用代码指定了主键是什么(或标识唯一记录的方式)。

To be honest, trying to dynamically grab a unique record based on a constant primary key value is pretty crazy - what if it's a composite key? 老实说,尝试根据恒定的主键值动态获取唯一记录是非常疯狂的- 如果它是复合键,该怎么办? I can't see how that code would work. 我看不到该代码将如何工作。

Happy to see other answers, but i would keep it simple. 很高兴看到其他答案,但我会保持简单。

If you want the code to grab the entity set based on T, i can share that - but it's pretty simple. 如果您想让代码获取基于T的实体集,我可以分享-但是非常简单。

If you want a method to grab a single record, let the calling code supply the predicate/key: 如果您想要一个方法来获取一条记录,请让调用代码提供谓词/键:

public T FindSingle(Expression<Func<T,bool>> predicate)
{
   return _ctx.GetEntitySet<T>.SingleOrDefault(predicate);
}

Then if for example "Post" had a composite key of "PostName" and "PostType": 然后,例如,如果“ Post”具有“ PostName”和“ PostType”的复合键:

var singlePost = repository.FindSingle(post => post.PostName == "Foo" && post.PostType == "Question");

In your example, your repository is dictating your model, making each entity have a single column primary key. 在您的示例中,您的存储库决定了您的模型,使每个实体具有单个列的主键。

Your repository should aid your model, not define it. 您的存储库应该帮助您的模型,而不是对其进行定义。

EDIT - Code for GetEntitySet<T> , as requested 编辑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 );
}

Pretty simple, and quite safe, because _plularizer is of type System.Data.Entity.Design.PluralizationService , which is the same module that EF uses to create default entity set names. 非常简单,也很安全,因为_plularizer的类型为System.Data.Entity.Design.PluralizationService ,它与EF用于创建默认实体集名称的模块相同。

EntityContainerName is your container name for your entities. EntityContainerName是您的实体的容器名称。

Your _plularizer instance should be static , and kept thread-safe with a fully-locked singleton. _plularizer实例应为static ,并通过完全锁定的单例保持线程安全。

HTH. HTH。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM