0

I'm working on an MVC app. A lot of the views are search engine like, allowing the user to select parameters to get the data he wants.

I am looking for an efficient way to make dynamic calls to the database so that I can retrieve only the wanted data instead of taking a bunch of data and sorting them out.

So far I have been using Dynamic Linq, but I have had huge troubles working with this and I was wondering if there was anything better and less troublesome. The only factor is that I know the fields of the table I'm looking on, and I need to be able to use operators like >, < or =.

EDIT

Here's a table example based on my app:

TABLE CARD
(
    CARD_IDE INT NOT NULL IDENTITY,
    CARD_NAME VARCHAR(50) NOT NULL,
    CARD_NUMBER NUMERIC(4) NOT NULL,
    CARD_COLOR VARCHAR(10),
    CARD_MANA_COST VARCHAR(30),
    CARD_MANA_CONVT VARCHAR(3),
    CARD_TYPE VARCHAR(50),
    CARD_POWER VARCHAR(2),
    CARD_TOUGH VARCHAR(2),
    CARD_RARTY VARCHAR(1) NOT NULL,
    CARD_TEXT_ABILT VARCHAR(800),
    CARD_TEXT_FLAVR VARCHAR(800),
    CARD_ARTST_NAME VARCHAR(100),
    CARD_SET_IDE INT NOT NULL,
    CARD_FLAG_FACE INT NOT NULL DEFAULT 0,
    CARD_CHILD_IDE INT,
    CARD_MASTER_IDE INT,
    CARD_UNIT_COST NUMERIC(5,2) NOT NULL DEFAULT 0
)

And a few examples:

  1. A user look for any item which type is "Creature" (String), number is 3 and card set IDE is 6;
  2. Any cards which contains the word Rat;
  3. All the cards of color Blue and White which unit cost is higher than 3.00
  4. Any cards which power is less than 3 but higher than 1.

EDIT 2

After much research (and thanks to Chris Pratt below), I've managed to look a bit and dive into something.

Based on this:

First I create my object context like this:

var objectContext = ((IObjectContextAdapter) mDb).ObjectContext;

Then I create the ObjectSet:

ObjectSet<CARD> priceList = objectContext.CreateObjectSet<CARD>();

Then I check if any values as been chosen by the user:

if (keyValuePair.Key == CARDNAME)
{
    queryToLoad = TextBuilder.BuildQueryStringForTextboxValue(keyValuePair.Value);

    //valuesToUse.Add("CARD_NAME.Contains(\"" + queryToLoad + "\")");

    priceList = priceList.Where(_item => _item.CARD_NAME.Contains(queryToLoad)) as ObjectSet<PRICE_LIST>;
}

Where the queryToLoad is, in fact, the value to look for. Example: if my user search for an Angel, the queryToLoad will be "Angel". I'm trying to get to the result without having to rewrite my whole code.

And then I gather the result in a List like this:

listToReturn.AddRange(priceList.ToList());

HOWEVER: I have a problem using this approach. As the priceList = priceList.Where(_item => _item.CARD_NAME.Contains(queryToLoad)) as ObjectSet<PRICE_LIST>; like is struck, the value is always null and I don't know why.

4

1 回答 1

1

没有办法优化本质上是动态的东西。您在应用程序中唯一可以做的就是将最终用户选择的任何过滤器输入到Where子句中,并让 Entity Framework 以它认为合适的最有效方式从您的数据库中获取结果。

但是,如果存在某些已知的限制,您可能会做一些事情。至少,如果您知道要搜索哪些字段,则可以向数据库添加适当的索引,以便优化对这些特定字段的搜索。但是,您可能会达到过度优化的程度(如果您为每个字段编制索引,则还不如没有索引)。通常最好监控数据库处理的查询并根据实际用户行为为最常用的字段添加索引。

您还可以对查询使用存储过程进行调查。根据应用的过滤器的复杂性和数量,创建存储过程来处理查询可能很困难,但如果您可以将逻辑压缩到足以使其成为可能,那么使用存储过程将高度优化查询。

更新

这就是我构建查询的意思。我将在上面采用您的第一个用例场景。您有三个过滤器:类型、编号和 IDE。用户可以指定任何一个或两个、三个全部或一个都不指定。(我们假设它cardType是一个字符串,cardNumber并且cardIde是可为空的整数。

var cards = db.Cards;

if (!string.IsNullOrEmpty(cardType))
{
    cards = cards.Where(m => m.Type == cardType);
}

if (cardNumber.HasValue)
{
    cards = cards.Where(m => m.Number == cardNumber);
}

if (cardIde.HasValue)
{
    cards = cards.Where(m => m.IDE == cardIde);
}

return View(cards);

实体框架实际上不会发出查询,直到您执行需要查询数据的操作(遍历列表、计算项目等)。在那之前,您对 DbSet 所做的任何额外操作都只是附加到 EF 最终将发送的查询中。因此,您可以在最终使用最终结果之前,一次有条件地处理每个潜在过滤器,从而构建您的查询。

更新#2

抱歉,我上次更新时显然还没有喝足够的咖啡。显然存在类型问题。如果您将其存储db.Cardscards其中,则将是一个DbSet<Card>类型,而对任何调用的结果Where都是一个IQueryable<Card>类型,显然不能将其存储在同一个变量中。

所以你只需要最初将变量转换为对两者都有效的东西IEnumerable<Card>

IEnumerable<Card> cards = db.Cards;

那么你不应该得到任何类型错误。

于 2013-07-24T18:58:34.997 回答