可以使用没有上下文的实体吗? [英] Can I use entities without context?

查看:84
本文介绍了可以使用没有上下文的实体吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个用户实体,并创建了部分用户类,所以我可以添加一些方法与NHibernate)。我添加了 GetByID 以使用户更容易:

  public static User GetByID (int userID)
{
using(var context = new MyEntities())
{
return context.Users.Where(qq => qq.UserID == userID) 。单();
}
}

现在,我想要的业务逻辑做这样的事情:

  var user = User.GetByID(userID); 
var posts = user.GetAllPostsForThisMonth();
foreach(var post in posts)
{
Console.WriteLine(post.Answers.Count);
}

GetAllPostsForThisMonth()类似于 GetByID - 具有上下文,并在执行后立即处理。



通常我不能这样做因为当调用 post.Answers.Count 时,会出现上下文。这个,我认为,使我的方法没用?或者我错过了什么?我可以这样使用我的实体吗?或者我应该为我使用的每个单个查询创建方法(如 post.GetAnswersCount())?感谢您提前!

解决方案

您所感动的行为实际上是好的,因为它让你无法自拔。如果您被允许执行此操作,则会导致 n 往返数据库(其中 n 为每个这样的往返行程都将拉取所有答案的所有数据,当你想要的是 Count 。这可能会产生巨大的性能影响。



您想要做的是构建一个对象,该对象代表数据库中期望的所有信息,然后构造一个LINQ查询将实际加载到您希望使用的所有信息中。

  public class PostSummary 
{
public post post {get; set;}
public int AnswerCount {get; set;}
}

public IEnumerable< PostSummary> GetBufferMariesByUserAndDateRange(
int userId,DateTime start,DateTime end)
{
using(var context = new MyEntities())
{
return context.Posts
.Where(p => p.UserId == userId)
.Where(p => p.TimeStamp< start&& p.TimeStamp> end)
.Select新的PostSummary {Post = p,AnswerCount = p.Answers.Count()})
.ToList();
}
}

这产生一个单一的SQL查询,往返,生成您所需的信息,而无需加载大量不需要的信息。



更新



如果NHibernate可以像Java的Hibernate一样工作,也不会在上下文处理之后进行延迟加载。实体框架确实为您提供了许多选项:哪一个最适合您将取决于您的具体情况。例如:




  • 而不是将数据访问方法中的上下文范围保留,您可以使上下文持续更长时间(例如每次请求一次在Web应用程序中),以便延迟加载属性将继续超出您的数据访问方法。

  • 您可以热切地加载您认识的任何实体关联。



这是一个渴望加载的例子:

  public GetAllPostsAndAnswersForThisMonth()
{
using(var context = new MyEntities())
{
return context.Posts.Include(Answers)
.Where(p => p.UserID == UserID)
.ToList();
}
}

但是,由于Entity Framework基本上构成您的数据访问我仍然认为,最好的做法是创建一个类或一组类,准确地模拟业务层实际想要的数据层,然后使数据访问方法产生这些类型的对象。 / p>

Let's say I have a User Entity, and created partial User class so I can add some methods (like with NHibernate). I added GetByID to make getting user easier:

public static User GetByID(int userID)
{
    using (var context = new MyEntities())
    {
        return context.Users.Where(qq => qq.UserID == userID).Single();
    }
}

Now, somewhere in business logic I'd like to do something like this:

var user = User.GetByID(userID);
var posts = user.GetAllPostsForThisMonth();
foreach(var post in posts)
{
    Console.WriteLine(post.Answers.Count);
}

GetAllPostsForThisMonth() is similar to GetByID - has context and is disposing it right after execution.

Normally I can't do this because context is disposed when I call post.Answers.Count. This, I think, renders my methods useless... Or am I missing something? Can I anyhow use my entities like this? Or should I create method for every single query I use (like post.GetAnswersCount())? Thanks in advance!

解决方案

The behavior you're lamenting is actually good, because it keeps you from shooting yourself in the foot. If you had been allowed to do this, it would have cause n round-trips to the database (where n is the number of posts), and each one of those round-trips would have pulled all the data for all the Answers, when all you wanted was the Count. This could have an enormous performance impact.

What you want to do is construct an object that represents all the information you expect to need from the database, and then construct a LINQ query that will actually load in all the information you expect to use.

public class PostSummary
{
    public Post Post {get;set;}
    public int AnswerCount {get;set;}
}

public IEnumerable<PostSummary> GetPostSummariesByUserAndDateRange(
                                   int userId, DateTime start, DateTime end)
{
    using (var context = new MyEntities())
    {
        return context.Posts
               .Where(p => p.UserId == userId)
               .Where(p => p.TimeStamp < start && p.TimeStamp > end)
               .Select(new PostSummary{Post = p, AnswerCount = p.Answers.Count()})
               .ToList();
    }
}

This produces a single SQL query and, in a single round-trip, produces exactly the information you wanted without loading in a ton of information you didn't want.

Update

If NHibernate works anything like Java's Hibernate, it won't do lazy loading after the context is disposed, either. Entity Framework does give you a lot of options along these lines: which one works best for you will depend on your particular situation. For example:

  • Rather than keeping your context scoped inside the data-access method, you can make the context last longer (like once per request in a web application), so that Lazy loading of properties will continue to work beyond your data-access methods.
  • You can eagerly load whatever entity associations you know you're going to need.

Here's an example of eager loading:

public GetAllPostsAndAnswersForThisMonth()
{
    using (var context = new MyEntities())
    {
        return context.Posts.Include("Answers")
                   .Where(p => p.UserID == UserID)
                   .ToList();
    }
}

However, since Entity Framework basically constitutes your "Data Access" tier, I would still argue that the best practice will be to create a class or set of classes that accurately model what your business layer actually wants out of the data tier, and then have the data access method produce objects of those types.

这篇关于可以使用没有上下文的实体吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆