我正在尝试找出处理具有不同图形(相关实体)的对象的最佳方法,具体取决于它们使用的上下文。
例如,这是我的域对象的示例:
public class Puzzle
{
public Id{ get; private set; }
public string TopicUrl { get; set; }
public string EndTopic { get; set; }
public IEnumerable<Solution> Solutions { get; set; }
public IEnumerable<Vote> Votes { get; set; }
public int SolutionCount { get; set; }
public User User { get; set; }
}
public class Solution
{
public int Id { get; private set; }
public IEnumerable<Step> Steps { get; set; }
public int UserId { get; set; }
}
public class Step
{
public Id { get; set; }
public string Url { get; set; }
}
public class Vote
{
public id Id { get; set; }
public int UserId { get; set; }
public int VoteType { get; set; }
}
我想要了解的是如何根据我使用它的方式加载这些信息。
例如,在首页我有一个所有谜题的列表。在这一点上,我并不真正关心这个解决方案的解决方案或这些解决方案中的步骤(可能会变得非常沉重)。我想要的只是谜题。我会从我的控制器加载它们:
public ActionResult Index(/* parameters */)
{
...
var puzzles = _puzzleService.GetPuzzles();
return View(puzzles);
}
稍后对于拼图视图,我现在只关心当前用户的解决方案。我不想用所有解决方案和所有步骤加载整个图表。
public ActionResult Display(int puzzleId)
{
var puzzle = _accountService.GetPuzzleById(puzzleId);
//I want to be able to access my solutions, steps, and votes. just for the current user.
}
在我的IPuzzleService中,我的方法如下所示:
public IEnumerable<Puzzle> GetPuzzles()
{
using(_repository.OpenSession())
{
_repository.All<Puzzle>().ToList();
}
}
public Puzzle GetPuzzleById(int puzzleId)
{
using(_repository.OpenSession())
{
_repository.All<Puzzle>().Where(x => x.Id == puzzleId).SingleOrDefault();
}
}
延迟加载在现实世界中并不真正起作用,因为我的会话正在每个工作单元之后处理。我的控制器没有存储库的任何概念,因此不管理会话状态,并且在呈现视图之前无法保持它。
我正在试图弄清楚这里使用的正确模式是什么。我的服务上是否有不同的重载,例如GetPuzzleWithSolutionsAndVotes
或更具体的视图,例如GetPuzzlesForDisplayView
和GetPuzzlesForListView
?
我有道理吗?我离开基地了吗?请帮忙。
答案 0 :(得分:2)
我有一个类似的情况,我无法使用延迟加载。
如果你只需要一两个案例,那么你建议的最简单的方法就是创建单独的GetPuzleWithXYZ()方法。
您还可以使用流畅的界面创建一个小型查询对象。
像...一样的东西。
public interface IPuzzleQuery
{
IPuzzleLoadWith IdEquals(int id);
}
public interface IPuzzleLoadWith
{
ISolutionLoadWith WithSolutions();
IPuzzleLoadWith WithVotes();
}
public interface ISolutionLoadWith
{
IPuzzleLoadWith AndSteps();
}
public class PuzzleQueryExpressionBuilder : IPuzzleQuery, IPuzzleLoadWith, ISolutionLoadWith
{
public int Id { get; private set; }
public bool LoadSolutions { get; private set; }
public bool LoadVotes { get; private set; }
public bool LoadSteps { get; private set; }
public IPuzzleLoadWith IdEquals(int id)
{
Id = id;
return this;
}
public ISolutionLoadWith WithSolutions()
{
LoadSolutions = true;
return this;
}
public IPuzzleLoadWith WithVotes()
{
LoadVotes = true;
return this;
}
public IPuzzleLoadWith AndSteps()
{
LoadSteps = true;
return this;
}
}
然后您的Repository Get()方法可以实例化表达式构建器并将其传递给调用者
public Puzzle Get(Action<IPuzzleQuery> expression)
{
var criteria = new PuzzleQueryExpressionBuilder();
expression(criteria);
var query = _repository.All<Puzzle>().Where(x => x.Id == criteria.Id)
if(criteria.LoadSolutions) ....
if(criteria.LoadSteps) ....
if(criteria.LoadVotes) ....
...
...
return query.FirstOrDefault();
}
并且典型的通话看起来像......
Puzzle myPuzzle = Repository.Get(where => where.IdEquals(101).WithSolutions());
Puzzle myPuzzle = Repository.Get(where => where.IdEquals(101).WithSolutions().AndSteps());
Puzzle myPuzzle = Repository.Get(where => where.IdEquals(101).WithVotes().WithSolutions());
它需要一点工作,但你可以看到基本的想法。
答案 1 :(得分:0)
我认为您的服务不应该对视图有任何了解。您的要求可能会发生变化,因此请勿将其名称与视图名称联系起来。
当您调用GetPuzzles()时,您应该只加载根难题,并且GetPuzzleById(int id)可以急切加载关联。
例如,在条件API中:.SetFetchMode("Solutions", NHibernate.FetchMode.Join)
我不明白你为什么懒得加载。如果您使用nHibernate,代理将在您访问该属性时返回数据库。您的控制器应该获得您需要的所有数据。您不应将未加载的代理传递给视图,然后您的视图必须处理无法加载数据的情况。
因此,您应该让控制器加载您需要的特定数据,仅为用户加载,我会更改界面,以便:GetPuzzle(puzzleId,user)
在这种方法中,您只需为一个用户加载数据即可。