🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
A few words on linq
This page was created by Alexandra on 2018-12-04. Last edited by Wikiadmin on 2026-09-12.
  1. A few words on LINQ

You can use LINQ in MDriven code to query objects already loaded in memory or to let MDriven translate a supported query into an OCLps query that retrieves matching objects from persistent storage.

Choose the right kind of query

MDriven objects are .NET objects. This means you can use ordinary LINQ over objects that are already available in your EcoSpace.

When the possible result set is large, use PSQuery<T>(). MDriven interprets the LINQ expression, translates it to OCLps (Object Constraint Language for Persistent Storage), and sends the query to the persistence storage. For a relational database, this means MDriven translates the query to SQL.

Your situation Use What happens
The objects are already loaded and you want to filter or project them in code Standard in-memory LINQ .NET evaluates the query over the objects in memory.
You need matching objects from persistent storage without loading every candidate object EcoSpace.PSQuery<T>() MDriven translates the supported LINQ expression to OCLps and retrieves the identities of matching objects. MDriven then resolves those identities to objects.
You are writing model rules, ViewModel expressions, derivations, or constraints OCL in the model MDriven type-checks the expression when the model is loaded, saved, or checked.

Use standard LINQ for objects in memory

Use normal LINQ when the collection you query is already in memory. For example, this query starts with all loaded instances of Class1, filters them by Attribute1, and returns the attribute values:

var standardLinq =
    from f in EcoSpace.Extents.AllInstances<Class1>()
    where f.Attribute1 == "1"
    select f.Attribute1;

This query does not ask persistent storage to find the matching objects. If Class1 contains many objects that have not been loaded, this approach can require MDriven to fetch objects while the query runs.

Use this approach when you already have the required objects or when the collection is small enough to process in memory.

Use PSQuery<T>() to filter in persistent storage

Use EcoSpace.PSQuery<T>() when you want persistent storage to identify the matching objects before MDriven loads them.

var matchingClass1 =
    from x in EcoSpace.PSQuery<Class1>()
    where x.Attribute1 == "1"
    select x;

foreach (Class1 item in matchingClass1)
{
    // Work with each fetched Class1 object.
}

int count = matchingClass1.ToArray().Length;

In this example, the query asks persistent storage for Class1 objects where Attribute1 is "1". It returns Class1 objects, not an untyped database result set.

This avoids loading every Class1 object only to discard most of them in a where clause. It is particularly important when the candidate set contains hundreds, thousands, or more objects.

Why this can be faster

A loop that accesses an unloaded relation can cause repeated lazy fetch operations. For example, if code iterates through many objects and accesses an unloaded relation for each one, MDriven may need to fetch data repeatedly.

A declarative query states the result you need. With PSQuery<T>(), MDriven can evaluate the supported filter in persistent storage and retrieve the matching object identities first. MDriven then performs its normal fetch operations to resolve those identities to objects.

What MDriven translates

A PSQuery<T>() expression is translated to OCLps, not directly written as database-specific SQL. OCLps is the persistence-storage subset of OCL. This lets the same model-oriented query approach work with the supported persistence mappers, including relational databases, XML, and memory-based persistence.

You can inspect the OCL expression produced by a persistence query:

var matchingClass1 =
    from x in EcoSpace.PSQuery<Class1>()
    where x.Attribute1 == "1"
    select x;

string ocl =
    (matchingClass1 as EcoQuery<Class1>)
        .GetResultingOclExpression();

For this example, the resulting OCL is similar to:

Class1.allInstances.select(GenSym_0|GenSym_0.Attribute1 = '1')

The generated variable name, such as GenSym_0, is an implementation detail. Focus on the query meaning: select all Class1 instances whose Attribute1 equals '1'.

Persistence-query limits

PSQuery<T>() is intended to find model objects in persistent storage. Its translated OCLps expression is a subset of OCL.

Keep these limits in mind:

- Select objects. Persistence queries retrieve object identities and MDriven resolves them to objects. - Do not expect tuple-producing operations to work. OCLps does not support collect, groupby, or other operators that return tuples. - Do not use operations with side effects. OCLps is a query language. - Do not expect every SQL function or every LINQ expression to be translatable. - Do not rely on your own model methods in OCLps, even if a method is marked IsQuery.

For example, this pattern stays within the intended use because it returns Class1 objects:

var matchingClass1 =
    from x in EcoSpace.PSQuery<Class1>()
    where x.Attribute1 == "1"
    select x;

By contrast, a projection that attempts to return a custom tuple is not a suitable persistence query result. Retrieve the matching objects first, then perform any object-level projection in memory.

For the complete OCLps rules and supported usage, see Documentation:OCLps.

Filter by subtype in persistent storage

Use OfType<T>() after a persistence query when you need persistent storage to restrict the result to a subclass.

var matchingSubclasses =
    (from v in EcoSpace.PSQuery<Class2>()
     where v.Class1.Attribute1 == "5" && v.Name == "5A"
     select v.Class1)
    .OfType<SomeSubClass>();

This query returns SomeSubClass objects whose related Class2 has the requested values. The subtype filter is part of the translated persistence query, so the filtering occurs before MDriven returns the objects.

See Documentation:Further Linq enhancements for the background and additional detail.

Do not use MemQuery<T>() when standard LINQ is enough

MDriven also provides EcoSpace.MemQuery<T>():

var memoryQuery =
    from x in EcoSpace.MemQuery<Class1>()
    where x.Attribute1 == "1"
    select x;

For ordinary in-memory work, prefer standard LINQ over the objects you already have. The standard LINQ form is clearer and does not require MDriven-specific query infrastructure.

LINQ in code; OCL in the model

Use LINQ when you need a query in C# code. LINQ is compiled and strongly typed, which helps you catch errors during compilation.

Use OCL when the rule belongs in the model. OCL is declarative: you describe the result or rule rather than the steps required to calculate it. MDriven uses OCL for model-level concepts such as constraints, derived attributes, derived associations, ViewModel columns and nestings, presentation expressions, action enable expressions, and state-machine guards.

For example, an OCL constraint or derivation can express a rule once in the model rather than repeating equivalent C# code across clients. MDriven dynamically type-checks OCL, EAL, and OCLps when the model is loaded, saved, or checked with ModelCheck.

OCL expressions have no side effects. When you need to change data in model-defined behavior, MDriven uses EAL (Extended Action Language), which uses the same syntax family for actions.

Read Documentation:OCL Expressions and Documentation:Learn OCL for OCL usage, and Training:Certain important constructs for methods and the IsQuery distinction.

Derived values and persistence queries

A derivation defined in the model is not itself available as a database column. When a LINQ or OCL query is translated for persistent storage, MDriven expands derivations into their persistent members so that the query can be evaluated.

For example, if Apartment.TheDogs is derived from occupants and pets, a persistence query for apartments with a dog named Benji must ultimately query the underlying Occupants, Pets, and PetType members.

See Documentation:Derivation is not available in the database for the derivation-expansion behavior and examples.

When to use other persistent-storage features

Use PSQuery<T>() when your code needs a set of model objects matching a supported predicate. If you need database-oriented aggregate work over very large data sets, or direct persistent-storage access from a ViewModel, review Documentation:PSExpression , or how to do things in the DB from MDriven. That page also points to the newer PSEval, PSEvalValue, and PSEvalTuple approaches.

Summary

1. Use standard LINQ for objects already in memory. 2. Use EcoSpace.PSQuery<T>() to have persistent storage filter a large candidate set and return matching objects. 3. Keep persistence queries within the OCLps subset: query-only, object-oriented, and without tuple-producing operations. 4. Use LINQ for C# code and OCL for rules that belong in the model. 5. Inspect the generated OCL when you need to understand how a PSQuery<T>() expression is interpreted.


❗🕜 Warning: this article may contain outdated information. Consider before using any descriptions/solutions, otherwise, it can still be helpful. Help: Synonyms and name changes

Standard LINQ syntax in MDriven code: <html>

<span style="background: white; color: blue;">var </span><span style="background: white; color: black;">standardlinq = </span><span style="background: white; color: blue;">from </span><span style="background: white; color: black;">f </span><span style="background: white; color: blue;">in </span><span style="background: white; color: black;">EcoSpace.Extents.AllInstances<</span><span style="background: white; color: #2b91af;">Class1</span><span style="background: white; color: black;">>() </span><span style="background: white; color: blue;">where </span><span style="background: white; color: black;">(f.Attribute1 == </span><span style="background: white; color: #a31515;">"1"</span><span style="background: white; color: black;">) </span><span style="background: white; color: blue;">select </span><span style="background: white; color: black;">f.Attribute1;
</span>

Why do we do that when standard Linq is just fine?

The object-oriented model-driven layer in ECO uses the language OCL – object constraint language – as specified by the OMG standard.

How do you use Linq in persistence storage in ECO?

Basic ECO query syntax: <html>

      <span style="background: white; color: blue;">var </span><span style="background: white; color: black;">z = </span><span style="background: white; color: blue;">from </span><span style="background: white; color: black;">x </span><span style="background: white; color: blue;">in </span><span style="background: white; color: black;">EcoSpace.PSQuery<</span><span style="background: white; color: #2b91af;">Class1</span><span style="background: white; color: black;">>() </span><span style="background: white; color: blue;">where </span><span style="background: white; color: black;">(x.Attribute1 == </span><span style="background: white; color: #a31515;">"1"</span><span style="background: white; color: black;">) </span><span style="background: white; color: blue;">select </span><span style="background: white; color: black;">x;
      </span><span style="background: white; color: blue;">foreach </span><span style="background: white; color: black;">(</span><span style="background: white; color: #2b91af;">Class1 </span><span style="background: white; color: black;">y </span><span style="background: white; color: blue;">in </span><span style="background: white; color: black;">z)
      {
        </span><span style="background: white; color: green;">// do somthing on each fecthed
      </span><span style="background: white; color: black;">}
      </span><span style="background: white; color: blue;">int </span><span style="background: white; color: black;">c = z.ToArray().Count();
</span>

Cast to EcoQuery to execute against storage: <html>

<span style="background: white; color: black;">(z </span><span style="background: white; color: blue;">as </span><span style="background: white; color: #2b91af;">EcoQuery</span><span style="background: white; color: black;"><</span><span style="background: white; color: #2b91af;">Class1</span><span style="background: white; color: black;">>).GetResultingOclExpression()
</span>

This translates to the following OCL query:

<span style="background: #e6e7e8; color: #1e1e1e;">"Class1.allInstances.select(GenSym_0|GenSym_0.Attribute1 = '1')"</span>

Alternatively, use ECO LINQ syntax directly:

<span style="background: white; color: blue;">var </span><span style="background: white; color: black;">ecolinq = </span><span style="background: white; color: blue;">from </span><span style="background: white; color: black;">x2x </span><span style="background: white; color: blue;">in </span><span style="background: white; color: black;">EcoSpace.MemQuery<</span><span style="background: white; color: #2b91af;">Class1</span><span style="background: white; color: black;">>() </span><span style="background: white; color: blue;">where </span><span style="background: white; color: black;">(x2x.Attribute1 == </span><span style="background: white; color: #a31515;">"1"</span><span style="background: white; color: black;">) </span><span style="background: white; color: blue;">select </span><span style="background: white; color: black;">x2x; </span><span style="background: white; color: green;">// rather use standard memory linq than this
</span>