Solved

Linq - Add custom calculated property based on other properties

Posted on 2008-10-19
8
3,757 Views
Last Modified: 2013-11-11
Hi i have a DataContext where i have tabel called tbl_ingredient.
this table holds alot of values.
however one of the values i need is calculated using some of the other fields.

I tried adding the property in another file as a partial class compiles well but gives me an error at runtime:
"Could not translate expression "

Cant i create a property like this ?

public partial class tbl_ingredient
    {
        public decimal ingredient_price_pr
        {
            get { return this._ingredient_price / this._ingredient_quantity; }
        }
 
    }

Open in new window

0
Comment
Question by:mSchmidt
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
8 Comments
 
LVL 4

Accepted Solution

by:
novynov earned 500 total points
ID: 22752266
With Linq to SQL, you can do something like the above, as long you only reference this property in statements like the Select() statement - basically just selecting/reading the value. You would not be able to use it in a Where() or similar statement that will be translated into a SQL WHERE clause, since the LINQ to SQL provider has no translation for that expression into SQL - thus the exception you are getting.

That said, there is a way to do a Where() using this property. It would require that you force early execution of the Linq to SQL expression by calling something like ToList() on the query. Once this is done, you are no longer operating with the Linq to SQL provider, you are now in the land of Linq to Objects...and doing a Where() with that property against the returned list of objects is completely valid. The downside is that you will get early execution of the SQL...even if you never iterate the collection.

Let me know if you need more info, or are still having problems.

0
 

Author Comment

by:mSchmidt
ID: 22752321
hmm iam actually not using it in a where statement, however i was using it within a query which i CONCAT with another query.
And if i execute these queries without Concat there is no problem, however using concat throws me the error, any idea why this is ?
0
 

Author Comment

by:mSchmidt
ID: 22752327
Just tried your idea with early execution and then it works

THIS WORKS
RadGrid_Details.DataSource = que2.ToList().Concat(que.ToList());

THIS DOESNT
RadGrid_Details.DataSource = que2.Concat(que);
0
Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

 
LVL 4

Expert Comment

by:novynov
ID: 22753095
Can you give me the code for your two queries? I suspect that the reason you are getting the exception is due to what I mentioned above. Where() isn't the only statement that will cause the behavior. It all has to do with how Linq to Sql translates each of the Linq extension methods to SQL. I suspect something in that translation is stumbling on a reference to your added property.

If I can see both queries, I should be able to analyze them and tell you what in which query is causing the hiccup.
0
 

Author Comment

by:mSchmidt
ID: 22753111
Sture here you go, as you can see my current impentation usesearly execution

private void rebindDetails()
        {
            var que =
                (from v in myData.tbl_calculation_details
                 join a in myData.tbl_calculations on v.calculation_calculation equals a.calculation_id
                 where v.calculation_id == selectedID
                 select new
                 {
                     id = v.id,
                     internt = a.calculation_number,
                     eksternt = "Kalkyle",
                     tekst = a.calculation_name,
                     amount = v.calculation_amount,
                     vGroup = v.calculation_group_name,
                     svind = (decimal)0,
                     prcPr = (decimal)200,
                     brand = "-",
                     unit = a.tbl_unit.unit_abbreviation  
                 }
                      );
                     
             var que2=
                      (
                          from v in myData.tbl_calculation_details
                          join a in myData.tbl_ingredients  on v.calculation_ingredient equals a.ingredient_id
                          where v.calculation_id == selectedID
                          select new
                          {
                              id = v.id,
                              internt = a.ingredient_itemnumber,
                              eksternt = a.ingredient_itemnumber_creditor.ToString(),
                              tekst = a.ingredient_name,
                              amount = v.calculation_amount,
                              vGroup = v.calculation_group_name,
                              svind = a.ingredient_loss,
                              prcPr = a.ingredient_price_pr,
                              brand = a.ingredient_brand,
                              unit = a.tbl_unit.unit_abbreviation
                          }
                      );


            RadGrid_Details.DataSource = que2.ToList().Concat(que.ToList()).OrderBy(a=>a.brand );
            RadGrid_Details.Rebind();
        }
0
 
LVL 4

Expert Comment

by:novynov
ID: 22753226
Hmmm...Am I correct to assume that the only calculated field in these 2 queries is a.ingredient_price_pr?

I'm trying to reproduce the behavior in some other data,  and so far am not having a problem.

Assuming this is the only calculated field, have you tried commenting out the prcPr from your anonymous type in both queries...and run it again without the ToList() calls? Does it still fail?
0
 

Author Comment

by:mSchmidt
ID: 22753267
Yep tried that

Then it doesnt fail :)
0
 
LVL 4

Expert Comment

by:novynov
ID: 22753474
So, it appears that in cases where a computed field is used in a final/tail Select() statement,  Linq to SQL is smart enough to just do the proper column selection (in your case selecting both columns that make up your computed field), and then reference the computed field locally.

However, in the case of Concat(), the SQL generated includes a UNION (not surprising) and the Linq to SQL provider apparently chokes if either side of the UNION contains a computed field. This makes sense when you look at the generated SQL. The Linq provider does a select (this is the final select where computed fields would work) against a union of 2 other selects...i.e. both of your queries. If either of those "inner" queries contains a computed field - you'll see the exception.

So, at this point, I believe your choices are:
1) Do the ToList() - with the risks aforementioned.
2) Change the select in the offending query to do the computation as part of the select. See snippet below. This doesn't read as elegantly...and decreases encapsulation and reuse...but will work.

I'm giving some thought to a more elegant solution that would involve delaying the reference to the computed field until the very end...but it may be difficult since your source data of both queries is shaped differently. I'll let you know.

I hope this helps.

Change:
 
prcPr = a.ingredient_price_pr,
 
To:
 
prcPr = a._ingredient_price / a._ingredient_quantity

Open in new window

0

Featured Post

Secure Your Active Directory - April 20, 2017

Active Directory plays a critical role in your company’s IT infrastructure and keeping it secure in today’s hacker-infested world is a must.
Microsoft published 300+ pages of guidance, but who has the time, money, and resources to implement? Register now to find an easier way.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question