gpt4 book ai didi

c# - 扩展 IQueryable 查询的属性

转载 作者:太空狗 更新时间:2023-10-29 21:55:52 24 4
gpt4 key购买 nike

我有以下虚构的域类:

public class Pony
{
public string Name { get; set; }
public DateTime FoundDate { get; set; }
}

public class Person
{
public ICollection<Pony> Ponies { get; private set; }

public Pony NewestPony
{
get
{
return Ponies
.OrderBy(pony => pony.FoundDate)
.FirstOrDefault();
}
}
}

NewestPony 属性封装了一个域规则,用于确定幸运者找到的最新小马。

我可以使用 Enumerable 扩展方法来使用这个属性:

IEnumerable<Person> people = GetPeople();
people.Where(p => p.NewestPony != null);

这太棒了。

但是,people 是 SQL Server(在本例中为 NHibernate)的 IQueryable 门面,查询必须由查询提供程序处理并转换为 SQL。因为数据库中没有物理的“NewestPony”列,所以查询提供程序会阻塞查询。

为了解决这个问题,我可以扩展查询中的属性,将其替换为它的 get 实现:

IEnumerable<Person> people = GetPeople();
person.Where(p
=> p.Ponies.OrderBy(pony => pony.FoundDate).FirstOrDefault() != null);

因为查询提供程序了解 SQL Server 中的关系,所以它现在可以评估此​​查询。

这个解决方案虽然可行,但确实复制了之前封装的规则。我正在寻找一种方法来避免这种重复行为,甚至可能是一种方法来扩展查询提供程序中的属性以允许它生成正确的 SQL 语句。

最佳答案

您遇到了一个典型的问题。有几种方法可以解决这个问题。如果您使用某些自动映射,则应排除该属性,如果您使用法线映射(HBM 文件),则可以忽略该属性。但是对于 LINQ 语句,它可能仍然会像您解释的那样出错。以下是一些解决方法:

  1. 务实:您对 POCO 的所有扩展都应该是方法,而不是属性。这反射(reflect)了你在做什么:一个有返回的行动。因此,使用 Pony GetNewestPony() 作为声明。我用 GetFullName() 在 POCO 中以同样的方式解决了这个问题,它结合了名字、中间名和姓氏。
  2. 设计:最好让您的 POCO 简单明了。这样它们就可以自动生成并且可以在不伤害任何人的情况下进化。只是 gettors/settors 而已。那么要解决您的问题:使用 C# 在 3.0 中引入的内容:扩展方法(不,扩展属性不存在)。
  3. 架构:通常将 DAO 层作为单独的层放置在与域层不同的组件中。这样,业务逻辑(获取选择、全部、更新、所有 CRUD 等)都可以放在自己的 DAO 类中。要做到这一点,您需要过度使用和理解 C# 接口(interface)和泛化。这个概念是explained clearly and detailed by Billy McCafferty后来演变成现在著名的S#arp Architecture .

快速修复:使用 nr 1 或 2。为了彻底的面向 future 的修复,改变你的架构,否则 NHibernate 会在背后咬你,而不是帮助你。

编辑:
下面,adriaanp 谈到了使用扩展方法的痛处,我相信他是对的。因为我几乎总是使用自动生成的 DTO,所以我希望它们与我手动引入的任何方法完全分开。如果我想在对象上使用它们,而不是作为扩展方法,Microsoft 正是为此目的引入了 partial 类(在类本身中扩展自动生成的类,而不会丢失往返工程)。但这里也是:小心不要弄得乱七八糟,清晰的文件名会有很大帮助。

关于c# - 扩展 IQueryable 查询的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3317214/

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