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

发布于 2024-10-04 05:43:26 字数 828 浏览 3 评论 0原文

我正在将 ORM 从 LINQ 转换为 SQL 到实体框架,并且正在更新我的存储库。除了通用的之外,所有这些都已完成。我似乎不知道如何将我的 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 的人可以转换该语句,我会很高兴。如果有替代代码可以完成同样的事情,我对此持开放态度。

I'm converting from LINQ to SQL to Entity Framework for my ORM and I'm updating my repositories. 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. 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.

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. If there's alternative code to accomplish the same thing, I'm open to it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迷你仙 2024-10-11 05:43:26

如果我正确理解该方法,它会根据主键返回任何类型 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 的代码,根据要求

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。

If i understand that method correctly, it returns a single record for any type T, based on a primary key.

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.

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":

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

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.

EntityContainerName is your container name for your entities.

Your _plularizer instance should be static, and kept thread-safe with a fully-locked singleton.

HTH.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文