gpt4 book ai didi

c# - 如何重构我的 LinqToSql 以使其更易于维护?

转载 作者:行者123 更新时间:2023-11-30 15:06:27 26 4
gpt4 key购买 nike

我正在使用 Linq2Sql 作为我的数据访问,但我很快注意到我做错了什么。

我有一个帖子列表,我需要能够以几种不同的方式对其进行过滤。例如:

  • GetNewest()
  • GetOldest()
  • GetForUser(int)
  • GetByCategory(整数)

每个方法都返回一个模型,我称之为 PostViewModel。它是帖子的扩展版本,以及它的一些外键。 (作者姓名等...)

帖子看起来像:

class Post
{
int Id;
DateTime DateCreated;
int AuthorId;
}

并且 PostViewModel 将是:

class PostViewModel
{
int Id;
DateTime DateCreated;
string AuthorName;
}

上面的每个方法都是类似

from p in db.Posts
where p.StatusID == (int)PostStatus.Visible //this can be different for each
order by <something> //this can be different for each
select new PostViewModel() //this is the same for each
{
//snip
}

我觉得我做错了什么。如果我对 PostViewModel 进行更改,我将不得不更改每个方法。可能需要注意的是,我将对象扩展到 PostViewModel 中,这样每当我遍历结果并显示它时,就不必返回数据库来获取 AuthorName(和其他一些)。

Sp 我可以在这里做什么?如果需要,我不怕做出重大改变。

最佳答案

首先,如果您的查询相对简单,我倾向于避免创建一组数据访问辅助方法,例如 GetNewest() , GetOldest() , GetForUser(int) , GetByCategory(int)等。这些类型的方法可能会适得其反,因为它们隐藏了对调用代码可能很重要的底层细节,并且使组合查询变得困难。

例如,您可以实现 GetNewest()像这样:

public IQueryable<Post> GetNewest()
{
return
from p in db.Posts
orderby p.DateCreated descending
select p;
}

但稍后包括 where p.StatusID == (int)PostStatus.Visible像这样的子句:

public IQueryable<Post> GetNewest()
{
return
from p in db.Posts
where p.StatusID == (int)PostStatus.Visible
orderby p.DateCreated descending
select p;
}

现在,所有调用代码仍显示为 GetNewest()因此,仅通过查看调用代码,您不知道您是否可见或顺序是什么。事实上,一些现有代码可能期望 GetNewest()返回不可见的帖子,现在您已经在没有意识到的情况下破坏了该代码。

另一方面,您不希望查询散布在整个代码中。如果您更改数据库模式,那么您可能会有很多损坏的代码。

正确的做法是将查询视为一系列可组合的原子操作。

所以这就是我建议您对数据访问代码执行的操作:

public static IQueryable<Post> WhereStatusVisible(
this IQueryable<Post> posts)
{
return
from p in posts
where p.StatusID == (int)PostStatus.Visible
select p;
}

public static IQueryable<Post> OrderByDateCreatedDescending(
this IQueryable<Post> posts)
{
return
from p in posts
orderby p.DateCreated descending
select p;
}

现在你可以写这样的调用代码了:

var query =
db.Posts
.WhereStatusVisible()
.OrderByDateCreatedDescending();

这变得非常清楚发生了什么,这些扩展方法的底层实现不太可能发生变化,所有模式细节都隐藏在扩展方法中。

然后您可以扩展它来处理 View 模型的创建。现在,由于 View 模型不是您数据库的一部分,我将从 IQueryable<Post> 开始至 IEnumerable<PostViewModel>因为看起来你需要加入作者(大概来自 User 表)我会做这样的事情:

public static IEnumerable<PostViewModel> ToPostViewModels(
this IQueryable<Post> posts,
IQueryable<User> users)
{
var query =
from p in posts
join u in users on p.AuthorId equals u.Id
select new { p, u };

return
query
.ToArray()
.Select(q => new PostViewModel()
{
Id = q.p.Id,
DateCreated = q.p.DateCreated,
AuthorName = q.u.Name,
})
.ToArray();
}

现在调用代码如下所示:

var postViewModels =
db.Posts
.WhereStatusVisible()
.OrderByDateCreatedDescending()
.ToPostViewModels(db.Users);

然后我也会考虑做这种代码:

public static IQueryable<Post> GetByCategories(
this IQueryable<Post> posts,
IQueryable<Category> categories)
{
return
from p in posts
join c in categories on p.CategoryId equals c.Id
select p;
}

public static IQueryable<Category> WhereStartsWith(
this IQueryable<Category> categories,
string startsWith)
{
return
from c in categories
where c.Name.StartsWith(startsWith)
select c;
}

这将启用这种调用代码:

var postViewModelsInCategoriesStartingWithN =
db.Posts
.GetByCategories(db.Categories.WhereStartsWith("N"))
.WhereStatusVisible()
.ToPostViewModels(db.Users);

所以这种方法的底线是你:

  1. 提供作用于 IQueryable<T> 的原子的、可组合的操作符去IQueryable<T> .
  2. 使用IQueryable<>在数据库中时转到 IEnumerable<>当您使用非数据库类时。
  3. 避免使您的调用代码依赖于数据库细节(即不要通过 int 获得,通过 UserIQueryable<User> 获得)。

如果有任何进一步的让我知道。我希望这会有所帮助。

关于c# - 如何重构我的 LinqToSql 以使其更易于维护?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7815702/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com