1
1

Hi,

I'm curious how I can solve this. In our model in an entity a field has been added that has a calculated result. The field is not marked with the [Field] attribute which obviously results in the error in the header:

Field 'order.Total' must be persistent (marked by [Field] attribute).

How can I use calculated fields in LINQ to DO.

Another issue with LINQ to DO is another calculated field. In a query I've had to add the composition of a Name like so:

        /// <summary>
    /// This routine retrieve all children of a Folder (Folders and Objecten).
    /// </summary>
    private static IQueryable<OpdrachtgeverHierarchy> GetFolderChildren(BaseFolder baseFolder)
    {
        var qFolders = from folder in baseFolder.BaseFolderList
                       select new OpdrachtgeverHierarchy
                       {
                           Id = folder.Id,
                           Naam = folder.Naam,
                           ObjectType = "folder",
                           HasChildren = folder.BaseObjectList.Count() > 0 ||
                                         folder.BaseFolderList.Count() > 0
                       };

        var qObjecten = from obj in baseFolder.BaseObjectList
                        select new OpdrachtgeverHierarchy
                        {
                            Id = obj.Id,
                            Naam = obj.Straat + " " +
                                    obj.Huisnummer + " " +
                                    obj.Postcode + " " +
                                    obj.Plaatsnaam,
                            ObjectType = "object",
                            HasChildren = obj.BaseActiviteitList.Count() > 0
                        };

        return qFolders.Concat(qObjecten);
    }

Now I obviously don't want to do it this way because code reuse is impossible this way. I've tried adding a calculated property to the class. I've tried a method that gives me the string but all of this does not work.

So the real question behind all this is: How do I define calculated fields in such a way that they can be used with LINQ to DO?

Regards, Paul Sinnema

asked Oct 11 '12 at 10:27

Paul%20Sinnema's gravatar image

Paul Sinnema
261888896


3 Answers:

Hello Paul,

this could be accomplished by adding custom LINQ compiler.

Consider the following example:

[HierarchyRoot]
public class Order : Entity
{
   [Key, Field]
   public long Id { get; private set; }

   [Field]
   public decimal Price { get; set; }

   [Field]
   public int Amount { get; set; }

   public decimal Total { get { return Price * Amount; } }
}

[CompilerContainer(typeof (Expression))]
public static class MyCompilers
{
  [Compiler(typeof (Order), "Total", TargetKind.PropertyGet)]
  public static Expression OrderTotal(Expression order)
  {
    Expression<Func<Order, decimal>> orderTotal = o => o.Amount * o.Price;
    return orderTotal.BindParameters(order);
  }
}

There is an alternative approach. You could dynamically add substitutions to DomainConfiguration.LinqExtensions.

Expression<Func<Order, decimal>> orderTotal = o => o.Amount * o.Price;
domainConfiguration.LinqExtensions.Register(typeof (Order).GetProperty("Total"), orderTotal);

answered Oct 15 '12 at 05:42

Denis%20Krjuchkov's gravatar image

Denis Krjuchkov
179325

Hi,

I'm trying to implement the examples you gave but can not resolve the BindParameters method. Do I need a reference somewhere?

Regards Paul

(Dec 05 '12 at 10:24) Paul Sinnema Paul%20Sinnema's gravatar image

Hi Denis,

I found the BindParameters but I still get the same exception. here is the code of the Entity:

using System.Collections.Generic;
using System.Linq;
using Facades.ControlIT;
using Fortrus.Intranet.Domain;
using Xtensive.Orm;
using Xtensive.Core;
using System.Linq.Expressions;
using System;

namespace Projecten.Model.Entities
{
/// <summary>
/// De opdrachtgever is een placeholder voor de opdrachtgever in Control IT.
/// Alle informatie komt dus uit Control IT m.u.v. de velden die specifiek 
/// voor PAD bedoeld zijn.
/// </summary>
[TableMapping("Opdrachtgever")]
public partial class OpdrachtgeverEntity : RootEntity
{
    #region DataObjectsFields

    /// <summary>
    /// Dit Id is de verbinding van deze class met de opdrachtgever in Control IT.
    /// </summary>
    [Field(Nullable = false)]
    public int CitOpdrachtgeverId { get; set; }

    /// <summary>
    /// Een opdrachtgever heeft een lijst van Baseline groepen.
    /// Een groep kan ook van het type Baseline zijn.
    /// </summary>
    [Field(LazyLoad = true)]
    [Association(OnOwnerRemove = OnRemoveAction.Cascade, OnTargetRemove = OnRemoveAction.Clear, PairTo = "Opdrachtgever")]
    public EntitySet<BaselineFolderEntity> BaselineFolderList { get; set; }

    /// <summary>
    /// Een opdrachtgever heeft een lijst van Groepen.
    /// Een groep kan ook van het type Project zijn.
    /// </summary>
    [Field(LazyLoad = true)]
    [Association(OnOwnerRemove = OnRemoveAction.Cascade, OnTargetRemove = OnRemoveAction.Clear, PairTo = "Opdrachtgever")]
    public EntitySet<PadFolderEntity> PadFolderList { get; set; }

    #endregion

    public OpdrachtgeverEntity()
        : base() 
    {
    }

    /// <summary>
    /// Haal de beschrijving op van de opdrachtgever uit Control IT
    /// </summary>
    public string Beschrijving
    {
        get
        {
            return Opdrachtgever.Naam;
        }
    }
}

[CompilerContainer(typeof(Expression))]
public static class MyCompilers
{
    [Compiler(typeof(OpdrachtgeverEntity), "Beschrijving", TargetKind.PropertyGet)]
    public static Expression Beschrijving(Expression opdrachtgever)
    {
        Expression<Func<OpdrachtgeverEntity, string>> beschrijving = o => o.Opdrachtgever.Naam;
        return beschrijving.BindParameters(opdrachtgever);
    }
}
}

answered Dec 05 '12 at 11:09

Paul%20Sinnema's gravatar image

Paul Sinnema
261888896

edited Dec 05 '12 at 12:29

Denis%20Krjuchkov's gravatar image

Denis Krjuchkov
179325

If I use o.Beschrijving instead of o.Opdrachtgever.Naam I get a StackOverflowException.

(Dec 05 '12 at 11:12) Paul Sinnema Paul%20Sinnema's gravatar image

Is your Opdrachtgever.Naam property defined as a regular [Field]?

(Dec 05 '12 at 12:33) Denis Krjuchkov Denis%20Krjuchkov's gravatar image

No, that field comes from our legacy (LINQ to SQL).

(Dec 06 '12 at 05:24) Paul Sinnema Paul%20Sinnema's gravatar image

Hi Denis,

Thanks for the assistance during our chat. Below are the conclusions of that conversation:

  • The Compiler attributes can only be used for fields that can be resolved as part of the SQL that is genereted for the database. Any fields that are not marked as [Field] can not be used in LINQ to Dataobjects.Net.
  • If you want to sort using LINQ one has to add .AsEnumerable().OrderBy(item => item.Sortfield) which will cause DO to fetch the data and LINQ to Objects will then sort the data client side.

Regards Paul

answered Dec 06 '12 at 07:31

Paul%20Sinnema's gravatar image

Paul Sinnema
261888896

edited Dec 06 '12 at 07:32

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×2
×1

Asked: Oct 11 '12 at 10:27

Seen: 5,420 times

Last updated: Dec 06 '12 at 07:32

Related questions

powered by OSQA