Какие Поддержки ORM это

В Windows с распределением ActiveState Perl используйте команда ppm.

5
задан Luke101 8 December 2009 в 01:51
поделиться

8 ответов

это можно сделать с помощью linq to sql ...

IQueryable<Article> query = yourDataContext.Articles;

if (catId > 0)
  query = query.Where(x => x.CategoryId == catId);

return query.ToList();
9
ответ дан 18 December 2019 в 06:02
поделиться

Вы можете легко создавать запросы таким образом, используя NHibernate HQL (Hibernate Query Language) . Это будет почти идентичная реализация, но я бы лично использовал параметры.

public List<Article> GetCat(int cat)

    {
        string qry = "select ap from Article a";
        if(cat > 0)
             qry += " where a.categoryID = :cat";

        IQuery query = session.CreateQuery(qry).SetInt32("cat",cat);

        return query.List<Article>();
    }

Это возвращает список <> объектов Article, готовых к использованию.

0
ответ дан 18 December 2019 в 06:02
поделиться

Не любите LLBLGen? Ну, он тоже может это сделать.

Использование стиля «адаптер»:

RelationPredicateBucket filters = new RelationPredicateBucket();
if (cat > 0)
    filters.Predicate.Add(Article.Fields.CategoryID == cat);
if (userId > 0)
    filters.Predicate.Add(Article.Fields.UserID == userId);
// And so on.

var adapter = new DataAccessAdapter();
var results = new EntityCollection<Article>(new ArticleFactory());
adapter.FetchEntityCollection(results, filters);

Я подозреваю, что большинство ORM справятся с этим довольно легко.

0
ответ дан 18 December 2019 в 06:02
поделиться

Я делаю такие вещи в NHibernate все время.

(Я делал подобные вещи в Rails. Я немного удивлен, что есть ORM, которые не поддерживают это.)

0
ответ дан 18 December 2019 в 06:02
поделиться

Вероятно, вы можете сделать это с любым поставщиком LINQ, но я знаю, что ORM LightSpeed ​​ поддерживает его:

var query = UnitOfWork.Articles;
if (cat > 0)
  query = query.Where(a => a.CategoryId == cat);
2
ответ дан 18 December 2019 в 06:02
поделиться

NHibernate поддерживает это с помощью API критериев:

ICriteria criteria = session.CreateCriteria<Article>();

if (cat > 0)
    criteria.Add(Expression.Eq("categoryID", cat));
6
ответ дан 18 December 2019 в 06:02
поделиться

You can use the Predicate Builder and LINQ to NHibernate to generate dynamic query's like this:

//using Predicate Builder
        public List<Location> FindAllMatching(string[] filters)
        {
           var db = Session.Linq<Location>();
           var expr = PredicateBuilder.False<Location>(); //-OR-
           foreach (var filter in filters)
           {
               string temp = filter;
               expr = expr.Or(p => p.Name.Contains(temp));
           }

           return db.Where(expr).ToList();
         }

You get the advantage of Type Save Query's and Compiler check.

You can also use the same approach of predicate builder with Linq to Sql and Entity Framework.

EDIT: Added example. It could be something like get all the locations matching N regions of the world, where the user select the regions he want to see, we don't know how many the user will select, we must build the (OR) expression on the fly, you can do something like:

public ActionResult Action(string[] filters)
{
    /*This values are provided by the user, maybe its better to use
     an ID instead of the name, but for the example is OK.
     filters will be something like : string[] filters = {"America", "Europe", "Africa"};
    */
    List<Location> LocationList = FindAllMatchingRegions(filters);
    return View(LocationList);
}

public List<Location> FindAllMatchingRegions(string[] filters)
        {
            var db = Session.Linq<Location>();
            var expr = PredicateBuilder.False<Location>(); //-OR-
            foreach (var filter in filters)
            {
                string temp = filter;
                expr = expr.Or(p => p.Region.Name == filter);
            }

            return db.Where(expr).ToList();
        }

You can Nest Predicates for a complex scenarios like this:

If you want to do something like

p => p.Price > 99 &&
     p.Price < 999 &&
     (p.Description.Contains ("foo") || p.Description.Contains ("far"))

you can build:

var inner = PredicateBuilder.False<Product>();
inner = inner.Or (p => p.Description.Contains ("foo"));
inner = inner.Or (p => p.Description.Contains ("far"));

var outer = PredicateBuilder.True<Product>();
outer = outer.And (p => p.Price > 99);
outer = outer.And (p => p.Price < 999);
outer = outer.And (inner);

And use it like :

var pr = db.Products.Where(outer).ToList();

The Predicate Builder Source and examples are available at http://www.albahari.com/nutshell/predicatebuilder.aspx

0
ответ дан 18 December 2019 в 06:02
поделиться

Как уже упоминалось здесь, LINQ позволяет расширить любой запрос, просто добавив к нему дополнительные критерии.

var query = 
  from x in xs 
  where x==1
  select x;

if (mustAddCriteria1)
  query = 
    from x in query 
    where ... // criteria 1
    select x;

if (mustAddCriteria2)
  query = 
    from x in query 
    where ... // criteria 2
    select x;

И так далее. Этот подход работает идеально. Но, вероятно, вы знаете, что компиляция запросов LINQ довольно затратна: например, Entity Framework может компилировать около 500 относительно простых запросов в секунду (см., Например, ORMBattle.NET ).

С другой стороны, многие инструменты ORM поддерживают скомпилированные запросы:

  • Вы передаете экземпляр IQueryable некоторому методу Compile и получаете делегат, позволяющий выполнять его намного быстрее. позже, потому что в этом случае не произойдет перекомпиляции.

Но если мы попытаемся использовать здесь этот подход, мы сразу заметим, что наш запрос на самом деле динамический: IQueryable , который мы выполняем каждый раз, может отличаться от предыдущий. Наличие частей запроса там определяется значениями внешних параметров.

Так можем ли мы выполнять такие запросы как скомпилированные, например, без явного кэширования?

DataObjects.Net 4 поддерживает так называемую функцию «логического ветвления». Это подразумевает, что любое постоянное логическое выражение оценивается во время компиляции запроса, и его фактическое значение вводится в SQL-запрос как истинная логическая константа (то есть не как значение параметра или как выражение, использующее параметры).

Эта функция позволяет создавать различные планы запроса в зависимости от на значениях таких логических выражений. Например, этот код:

  int all = new Random().Next(2);
  var query = 
    from c in Query<Customer>.All
    where all!=0 || c.Id=="ALFKI"
    select c;

будет выполняться с использованием двух разных SQL-запросов и, следовательно, - двух разных планов запросов:

  • План запроса на основе поиска по индексу (довольно быстро), если все == 0
  • План запроса на основе сканирование индекса (довольно медленное), если all! = 0

Случай, когда all == null, SQL-запрос:

SELECT
  [a].[CustomerId],
  111 AS [TypeId] ,
  [a].[CompanyName]
FROM
  [dbo].[Customers] [a]
WHERE(( CAST( 0 AS bit ) <> 0 ) OR( [a].[CustomerId] = 'ALFKI' ) );

Случай, когда all == null, план запроса:

|--Compute Scalar(DEFINE:([Expr1002]=(111)))
   |--Clustered Index Seek(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]), SEEK:([a].[CustomerId]=N'ALFKI') ORDERED FORWARD)

Второй случай (когда all! = Null), SQL-запрос:

SELECT
  [a].[CustomerId],
  111 AS [TypeId] ,
  [a].[CompanyName]
FROM
  [dbo].[Customers] [a]
WHERE(( CAST( 1 AS bit ) <> 0 ) OR( [a].[CustomerId] = 'ALFKI' ) );
-- Notice the ^ value is changed!

Второй случай (когда all! = Null), план запроса:

|--Compute Scalar(DEFINE:([Expr1002]=(111)))
   |--Clustered Index Scan(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]))
-- There is index scan instead of index seek!

Обратите внимание, что почти любой другой ORM скомпилирует это в запрос, использующий целочисленный параметр:

SELECT
  [a].[CustomerId],
  111 AS [TypeId] ,
  [a].[CompanyName]
FROM
  [dbo].[Customers] [a]
WHERE(( @p <> 0 ) OR ( [a].[CustomerId] = 'ALFKI' ) );
--      ^^ parameter is used here

Поскольку SQL Server (как и большинство баз данных) генерирует единственную версию плана запроса для конкретного запроса, в этом случае у него есть единственный вариант - сгенерировать план со сканированием индекса:

|--Compute Scalar(DEFINE:([Expr1002]=(111)))
   |--Clustered Index Scan(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]), WHERE:(CONVERT(bit,[@p],0)<>(0) OR [DO40-Tests].[dbo].[Customers].[CustomerId] as [a].[CustomerId]=N'ALFKI'))

Хорошо, это было «быстрое» объяснение полезности этой функции. Вернемся теперь к вашему случаю.

Логическое ветвление позволяет реализовать его очень просто:

var categoryId = 1;
var userId = 1;

var query = 
  from product in Query<Product>.All
  let skipCategoryCriteria = !(categoryId > 0)
  let skipUserCriteria = !(userId > 0)
  where skipCategoryCriteria ? true : product.Category.Id==categoryId
  where skipUserCriteria ? true : 
  (
    from order in Query<Order>.All
    from detail in order.OrderDetails
    where detail.Product==product
    select true
  ).Any()
  select product;

Пример отличается от вашего, но он иллюстрирует идею. Я использовал другую модель в основном для того, чтобы проверить это (мой пример основан на модели Northwind).

Это запрос:

  • Не динамический запрос, поэтому вы можете безопасно передать его методу Query.Execute (...) , чтобы он выполнялся как скомпилированный запрос.
  • Тем не менее, каждое его выполнение приведет к такому же результату, как если бы это было сделано с "добавление" к IQueryable .
10
ответ дан 18 December 2019 в 06:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: