Use the data context as a method argument in LINQPad - linq

I have a compiled assembly that contains a lot of my business logic rules which I would like to use inside of LINQ Pad. I can add a reference to the assembly using Query -> Query Properties, but once I have the reference how do I access the context?
My BL object expects an IMyDataSource object, not an individual IDbSet.
Normally in a LINQ Pad query, the individual DB sets are "magically" available via their names. For example
In normal .NET code I would write
Dim items As IQueryable(of Item) = DataSource.Items
but in LINQ Pad I would write it without a reference to the context.
Dim items = Items

Your LINQPad query is compiled into a sub-class of the Data Context, so your data source is available as Me. Therefor you can quality Items to Me.Items for the same result.

If you are using C# inside LINQPad, you can refer to the Data Context as simply this. For example, you can refer to the entity collection Items as this.Items and get the same results.

Related

Linq To Sql Where does not call overridden Equals

I'm currently working on a project where I'm going to do a lot of comparison of similar non-database (service layer objects for this discuss) objects and objects retrieved from the database via LinqToSql. For the sake of this discussion, assume I have a service layer Product object with a string field that is represented in the database. However, in the database, there is also a primary key Id that is not represented in the service layer.
Accordingly (as I often do for unit testing etc), I overrode Equals(Object), Equals(Product), and GetHashCode and implemented IEquatable with the expectation that I would be able to write code like this:
myContext.Products.Where(p => p.Equals(passedInProduct).SingleOrDefault();
And so forth.
The Equals override is tested and works. The objects are mutable so the usual caveats apply to the GetHashCode override. However, for the purposes of this example, the objects are not modified except by LtS and could be made readonly.
Here's the simple test:
Create a test object in memory and commit to the LtS context. By committing, the test object is populated with a few auto-generated fields.
Create another identical test object in memory (separate reference)
Attempt to retrieve the first object from the database using the second object as the criteria. (see code line above).
// Setup
string productDesc = "12A";
Product testProduct1 = _CreateTestProductInDatabase(productDesc);
Product testProduct2 = _CreateTestProduct(productDesc);
// check setup
Product retrievedProduct1 = ProductRepo.Retrieve(testProduct1);
//Assert.IsNotNull(retrievedProduct1);
// execute - try to retrieve the 'equivalent' product object
Product retrievedProduct2 = ProductRepo.Retrieve(testProduct2);
A simplified version of Retrieve (cruft removed is just parameter checks etc):
using (var dbContext = new ProductDataContext()) {
Product retrievedProduct = dbContext.Products
.Where(p => p.Equals(product)).SingleOrDefault();
NB: The overridden Equals method knows not to care about the auto-generated fields from the database and only looks at the string that is represented in the service layer.
Here's what I observed:
Retrieve on testProduct1 succeeds (no surprise, equal by reference)
Retrieve on testProduct2 fails (null)
The overridden Equals method called in the Retrieve method is never hit during either Retrieve calls
However, the overridden Equals method is called multiple times by the context on SubmitChanges (called when creating the first test object in the database) (works as expected).
Statically, the compiler knows that the type of the objects being emitted and is able to resolve the type.
So my specific questions:
Am I trying to do something ill-advised? Seems like a straightforward use of Equals.
Corollary to first question: alternate suggestions to deal with linq to sql equality checking while keeping comparison details inside the objects rather than the repository
Why might I have observed the Equals method being resolved in SubmitChanges but not in the Where clause?
I'm as much interested in understanding as making my Equals calls work. But I also would love to learn how to make this 'pattern' work rather than just understand why it appears to be an 'anti-pattern' in the contest of LtS and C#.
Please don't suggest I just filter directly on the context with Where statements. Obviously, I can remove the Equals call and do that. However, some of the other objects (not presented here) are large and a bit complicated. For the sake of maintenance and clarity, I want to keep knowledge of how to compare itself to another of its own type in one place and ideally as part of the object in question.
Some other things I tried that didn't change the behavior:
Overloaded and used == instead
Casting the lambda variable to the type p => (Product)p
Getting an IQueryable object first and calling Equals in the Where clause
Some other things I tried that didn't work:
Creating a static ProductEquals(Product first, Product second) method: System.NotSupportedException:has no supported translation to SQL.
Thanks StackOverflow contributors!
Re Possible dups: I've read ~10 other questions. I'd love a pointer to an exact duplicate but most don't seem to directly address what seems to be an oddity of LinqToSql.
Am I trying to do something ill-advised?
Absolutely. Consider what LINQ to SQL does: it creates a SQL representation of your query. It doesn't know what your overridden Equals method does, so can't translate that logic into SQL.
Corollary to first question: alternate suggestions to deal with linq to sql equality checking while keeping comparison details inside the objects rather than the repository
You'd need to do something with expression trees to represent the equality that way - and then build those expression trees up into a full query. It won't be fun, but it should be possible. It will affect how you build all your queries though.
I would have expected most database representations to be ID-based though, so you should be able to just compare IDs for equality. Usually when I've seen attempts to really model data in an OO fashion but store it in a database, the leakiness of the abstraction has caused a lot of pain.
Why might I have observed the Equals method being resolved in SubmitChanges but not in the Where clause?
Presumably SubmitChanges is working against a set of in-memory objects to work out what's changed - it doesn't have to do any conversion to SQL to do that part.

Define business methods usable by linq to entity and linq to objects

I use in my project a lot of LINQ queries and business methods.
To allow these business method to be used from an Iqueryable :
I defined UDF functions in SQL Server (with the needed parameters)
Add this UDF to the EDMX model of the application
And make a gateway between UDF and LinQ with a method like this in a
partial class who inherits from the dbcontext :
[EdmFunction("MyProject.Store", "GetTaxesOfProduct")]
public static Decimal GetTaxesOfProduct(Decimal amount, Int32 TaxMethod)
{
throw new NotSupportedException("Not direct access possible, use with E-SQL or LINQ");
}
This works perfectly for IQueryable.
But the problem is that, to use this method from a simple object (not linked to a database record), i need to make something creepy like this :
var query = from foo in context.JustATable select context.GetTaxesOfProduct(15.55, 3);
And recently i came across this http://blogs.msdn.com/b/charlie/archive/2008/01/31/expression-tree-basics.aspx who explain how, with expression, you can make a method who is usable from C# objects and IQueryable
So, with expression, is it possible to make business methods like my method but without the use of UDF and just expressions ?
Thank you by advance !
It depends on the content of your UDF. Expression can work only with entities defined in your model and use only operations provided by Entity Framework provider for your database. So if you use any complex SQL statement with not supported equivalent for LINQ or non mapped features inside your UDF it will not work.

Linq to entity - Call user defined method from query

In my project, i use several linq queries for getting prices list.
I need to calculate values based on these prices.
Is it possible to call a user method (who can, ideally, be in the entity class) directly from the linq query, for example, doing like this would be perfect
from foo in Foo
select new {
price = foo.Price,
priceclass = foo.GetClassOfPrice()
}
There would be no data access from GetClassOfPrice, just static code based on the price.
Thank's by advance !
Linq-To-Entities can call only special type of methods defined in conceptual model (EDMX). These methods are called Model defined functions. So if you define your method this way you will be able to call it. You can also check this blog post.
You can only call the method via LINQ to Objects as there is no translation to SQL for the method call. If you materialize the query -- bring it into memory -- first, then do the selection it should work.
var foos = context.Foo.ToList()
.Select( f => new
{
price = f.Price,
priceClass = f.GetClassOfPrice()
} );
Note that you should perform any conditional logic (Where) before doing the ToList so that you're only transferring the data that you actually need from the DB. I'm using extension methods because it's more natural for me and because you'd need to use the ToList or similar method anyway. I really dislike mixing LINQ syntax with the extension methods.
Unfortunately, this can't be done, because your LINQ query is translated to SQL. And your method isn't known to the so called provider that does this translation.
There are only a few functions that you can call when dealing with linq to entities and they are listed here:
http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions.aspx
http://msdn.microsoft.com/en-us/library/system.data.objects.entityfunctions.aspx

Workarounds for using custom methods/extension methods in LINQ to Entities

I have defined a GenericRepository class which does the db interaction.
protected GenericRepository rep = new GenericRepository();
And in my BLL classes, I can query the db like:
public List<Album> GetVisibleAlbums(int accessLevel)
{
return rep.Find<Album>(a => a.AccessLevel.BinaryAnd(accessLevel)).ToList();
}
BinaryAnd is an extension method which checks two int values bit by bit. e.g. AccessLevel=5 => AccessLevel.BinaryAnd(5) and AccessLevel.binaryAnd(1) both return true.
However I cannot use this extension method in my LINQ queries. I get a runtime error as follows:
LINQ to Entities does not recognize the method 'Boolean BinaryAnd(System.Object, System.Object)' method, and this method cannot be translated into a store expression.
Also tried changing it to a custom method but no luck. What are the workarounds?
Should I get all the albums and then iterate them through a foreach loop and pick those which match the AccessLevels?
I realize this already has an accepted answer, I just thought I'd post this in case someone wanted to try writing a LINQ expression interceptor.
So... here is what I did to make translatable custom extension methods: Code Sample
I don't believe this to be a finished solution, but it should hopefully provide a good starting point for anyone brave enough to see it through to completion.
You can only use the core extension methods and CLR methods defined for your EF provider when using Entity Framework and queries on IQueryable<T>. This is because the query is translated directly to SQL code and run on the server.
You can stream the entire collection (using .ToEnumerable()) then query this locally, or convert this to a method that is translatable directly to SQL by your provider.
That being said, basic bitwise operations are supported:
The bitwise AND, OR, NOT, and XOR operators are also mapped to canonical functions when the operand is a numeric type.
So, if you rewrite this to not use a method, and just do the bitwise operation on the value directly, it should work as needed. Try something like the following:
public List<Album> GetVisibleAlbums(int accessLevel)
{
return rep.Find<Album>(a => (a.AccessLevel & accessLevel > 0)).ToList();
}
(I'm not sure exactly how your current extension method works - the above would check to see if any of the flags come back true, which seems to match your statement...)
There are ways to change the linq query just before EF translates it to SQL, at that moment you'd have to translate your ''foreign'' method into a construct translatable by EF.
See an previous question of mine How to wrap Entity Framework to intercept the LINQ expression just before execution? and mine EFWrappableFields extension which does just this for wrapped fields.

Linq to NHibernate extensibility for custom string query operations?

I would like to be able to use custom string querying within my NHibernate Linq expressions. Let's say for example (and this is just an example) I would like to be able to select entities containing a property which is an anagram of a particular string:
var myEntities = EntityRepository.AllEntities.Where(x => x.Description.IsAnagramOf('hits');
I imagine the steps involved in this process would be:
Define a SQL Server UDF to determine
whether two strings are anagrams.
Define an extension method called
IsAnagramOf() for the String
class.
(And this is the tricky one). Modify
Linq to NHibernate's
component for parsing expression
trees so that it converts calls to
the extension method into the
appropriate SQL UDF call.
My question is this. Does Linq to NHibernate contain some kind of extensibility model enabling me to 'slot in' my own custom string operations, or would I literally have to modify the existing source code to add in my shiznit to the expression tree parsing component?
The extensibility is built in NH 3.0 (final release next month).
You can see a full working example at http://fabiomaulo.blogspot.com/2010/07/nhibernate-linq-provider-extension.html

Resources