使用 EF 4 创建 MustOverride(抽象)成员?

发布于 2024-10-17 04:41:33 字数 903 浏览 1 评论 0原文

我有一个抽象类Contact

它导致两个子类:

  1. Company (Title)
  2. Person (FirstName, LastName)

我想在 Person 表中添加一个计算的“Title”列,它返回 FirstName + ' ' + LastName,这将为我提供更好的搜索选项。

所以我想创建具有抽象属性 Title 的 Contact 表,这两个属性中的每一个都实现了该属性,因此,我将能够使用:

Dim contacts = From c In context.Contacts
               Where c.Title.Contains("Nash")

我很确定这是不可能的,问题是有效的替代方法是什么?

在我的场景中,我有一个列表框,显示公司和个人类型的所有联系人,我有一个搜索文本框,我想要服务查询(GetContacts(searchQuery As String) )根据数据库查询过滤后的集合。

更新
在 Will 回答之后,我决定在 Person 表中创建一个如上所述的计算列。 问题是实现 WCF-RIA 查询方法的最有效方法是什么:

Public Function GetContacts(searchQuery As String) As IQueryable(Of Contact)
  'Do here whatever it takes to retieve from Contacts + People 
  'and mix the results of both tables ordered by Title
End Function

I have an abstract class Contact.

It leads to two subclasses:

  1. Company (Title)
  2. Person (FirstName, LastName)

I want to add a computed 'Title' col in the Person table, that return FirstName + ' ' + LastName, which will give me better search options.

So I want to create the Contact table have an abstract property Title, which each of these two implements, and so, I will be able to use:

Dim contacts = From c In context.Contacts
               Where c.Title.Contains("Nash")

I am pretty sure this is impossible, the question is what is the efficient alternative way?

In my scenario I have a ListBox showing all the Contacts of both Company and Person types, I have a search TextBox and I want the Service query (GetContacts(searchQuery As String)) to query the filtered set against the DB.

Update
After Will's answer, I decided to create in the Person table a computed col as above.
The question is what what be the most efficient way to imlpement the WCF-RIA query method:

Public Function GetContacts(searchQuery As String) As IQueryable(Of Contact)
  'Do here whatever it takes to retieve from Contacts + People 
  'and mix the results of both tables ordered by Title
End Function

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

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

发布评论

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

评论(1

离笑几人歌 2024-10-24 04:41:33

不幸的是,虽然有一种方法可以使用 部分类 来做到这一点,但我 99% 确定你不能混合涉及实体属性和分部类中定义的“POCO”属性的 linq 查询。

Linq to Entity 上下文实际上会将这些查询转换为 sql,并且它无法处理上下文不直接支持特定方法的情况。 L2E 的一个常见示例是无法在查询中使用枚举。就像知道如何处理枚举一样,上下文当然不知道在转换为原始 sql 时如何处理 POCO 属性。

您可能想要研究的一个选项是在数据库中创建计算列,或者运行查询,执行传统的 ToArray() 以触发枚举,然后检查内存中的计算列。然而,这可能不是一个好的解决方案,具体取决于表的大小。


因此,本质上,您希望搜索两种不同的类型(由两个不同的表支持),然后组合结果以显示给用户。

我不得不说多态性不是最好的解决方案。在 UI 中显示它们的愿望不应该将设计决策一直强加到您的类型定义中。

我之前在 WPF 中做过几次类似的事情。我用两种方法做到了;通过使用外观类型形式的多态性来包装模型,并且可以通过公共基类型进行处理,并将集合中的所有不同类型视为 System.Object。

当您需要类型安全并且能够以相同方式处理不同类型时,第一种方法是可以的。包装器扩展了一个公共基类,并被编码为“知道”如何正确处理每个包装类型。

当您不需要类型安全时,例如将集合公开到 WPF 视图(其中您在 ItemsControl 中显示它们)时,第二种方法是可以的,它可以根据集合中每个实例的类型找出要使用的正确 DataTemplate。收藏。

我不确定哪种方式最适合您,但无论哪种方式,您都应该分别查询您的公司和个人表,联合两个结果集,然后对它们进行适当的排序。

伪代码:

//Wrapper version
var results  = Company
               .Where(x=>x.Title.Contains(searchTerm))
               .Select(x=> new CompanyWrapper(x))
               Cast<BaseWrapper>().Union(
                  Person
                      .Where(x=>x.ComputedTitle.Contains(searchTerm))
                      .Select(x=> new PersonWrapper(x))
                      .Cast<BaseWrapper>());

//System.Object version
var results  = Company
               .Where(x=>x.Title.Contains(searchTerm))
               Cast<object>().Union(
                  Person
                      .Where(x=>x.ComputedTitle.Contains(searchTerm))
                      .Cast<object>());

在这两种情况下,您可能不必专门进行向下转换。同样,如果您在 UI 中需要类型安全,第一个为您提供类型安全,第二个更简单,并且在后端需要更少的代码,但仅当您不需要 UI 中的类型安全时才有用。

至于排序,搜索并合并结果后,您可以 OrderBy 对结果进行排序,但是您必须提供一个可以执行排序的函数。此功能将根据您选择的版本而有所不同。

Unfortunately, while there is a way to do this with partial classes, I am 99% sure you cannot mix linq queries that touch entity properties and "POCO" properties defined in a partial class.

The Linq to Entity context will actually convert these queries to sql, and it cannot handle situations where a particular method isn't directly supported by the context. A common example for L2E is the inability to use enums in your query. Like knowing how to handle enums, the context certainly doesn't know how to handle your POCO properties when converting to raw sql.

An option you might want to investigate is to create a the computed column within your database, or to run your queries, do the traditional ToArray() in order to trigger enumeration, and then examine the computed column in memory. This might not be a good solution, depending on the size of your table, however.


So, essentially, you wish to search two disparate types (backed by two different tables) and then combine the results for display to the user.

I would have to say that polymorphism is NOT the best solution. The desire to show them in the UI shouldn't force a design decision all the way down into your type definitions.

I have done something similar a few times before in WPF. I've done it two ways; by using polymorphism in the form of facade types which wrap the models and which can be treated by a common base type, and by treating all the different types in the collection as System.Object.

The first way is okay when you need type safety and the ability to treat different types the same way. The wrappers extend a common base class and are coded to "know" how to handle each of their wrapped types correctly.

The second way is okay when you don't need type safety, such as when exposing a collection to a WPF View where you are displaying them in an ItemsControl, which can figure out the correct DataTemplate to use by the type of each instance in the collection.

I'm not sure which way is best for you, but whichever it is, you should query both your Company and Person tables separately, Union the two result sets, then sort them appropriately.

Pseudocode:

//Wrapper version
var results  = Company
               .Where(x=>x.Title.Contains(searchTerm))
               .Select(x=> new CompanyWrapper(x))
               Cast<BaseWrapper>().Union(
                  Person
                      .Where(x=>x.ComputedTitle.Contains(searchTerm))
                      .Select(x=> new PersonWrapper(x))
                      .Cast<BaseWrapper>());

//System.Object version
var results  = Company
               .Where(x=>x.Title.Contains(searchTerm))
               Cast<object>().Union(
                  Person
                      .Where(x=>x.ComputedTitle.Contains(searchTerm))
                      .Cast<object>());

In both cases, you may not have to downcast specifically. Again, the first gives you type safety if you need it in the UI, the second is simpler and requires less code on the backend but is only useful if you don't require type safety in the UI.

As for sorting, once you've searched and combined your result, you can OrderBy to sort the result, however you will have to provide a function which can perform the ordering. This function will differ depending on which version you choose.

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