how to do a Join in Entity Framework - c#

Instead of writing a linq query, is there a way I can just do a join by simply doing something like this:
using (var db = new MatchGamingEntities())
{
db.Accounts.Join() //I am unsure of the syntax
db.Accounts.Include...
...
return View(Account.SingleOrDefault());
}
I want to use these predefined Entity functions instead of writing linq, is it practical? Also how do you use these predefined functions? I have a table called "Accounts" and "BankTransactions" they both have AccountId in common, How would I query that using these functions and what type of result would it return its one to many relationship.

LINQ is really your better bet, things start to get hectic in Lambda's really fast and linq just looks a lot better given the structured way compared to lambda's
See this SO Post:
C# Joins/Where with Linq and Lambda
var query = db.Accounts.Join(db.BankTransactions,
acc => acc.AccountID,
bank => bank.AccountID,
(acc,bank) => new { Account = acc, BankTransaction = bank });
Edit:
This should(or something similar) return a query that will return a collection of Accounts and inside each account it's relevant BankTransaction.
This should do it but again, rather use LINQ if possible.
Edit: Just as an afterthought, you can add additional lamba extensions like a where clause to the above one.

Related

Passing a GetWhere query (Func<entityDTO,bool>) to a data layer method which needs a (Func<entity,bool>) parameter to work

I have the following method in a data access class which uses entity framework:
public static IEnumerable<entityType> GetWhere(Func<entityType, bool> wherePredicate)
{
using (DataEntities db = new DataEntities())
{
var query = (wherePredicate != null)
? db.Set<entityType>().Where(wherePredicate).ToList()
: db.Set<entityType>().ToList();
return query;
}
}
This works fine when I use the entities across all layers... however I am trying to move to using a DTO class and I would like to do something like the following:
public static IEnumerable<EntityTypeDTO> GetWhere(Func<EntityTypeDTO, bool> wherePredicate)
{
//call a method here which will convert Func<EntityTypeDTO,bool> to
// Func<EntityType,bool>
using (DataEntities db = new DataEntities())
{
var query = new List<EntityType>();
if (wherePredicate == null)
{
query = db.Set<EntityType>().ToList();
}
else
{
query = (wherePredicate != null)
? db.Set<EntityType>().Where(wherePredicate).AsQueryable<EntityType>().ToList()
: db.Set<EntityType>().ToList();
}
List<EntityTypeDTO> result = new List<EntityTypeDTO>();
foreach(EntityType item in query)
{
result.Add(item.ToDTO());
}
return result;
}
}
Essentially I want a method which will convert Func to Func.
I think I have to break down the Func into an expression tree and then rebuild it somehow in the entityType?
I want to do this to allow the Presentation Layer to just pass the Expression queries?
Am I missing something basic or is there an easier design pattern that can pass a query from a DTO to a data access class without knowing the details of the query?
I have tried making the DTO inherit from the entity which doesn't seem to work either?
If there is a better design pattern that I am missing I would love a pointer and I can investigate from there...
Firstly I would suggest that you put a querying layer of your own in front of Entity Framework rather than allowing any arbitrary Func to be passed in because it will be very easy in the future to pass a Func that Entity Framework can not translate into a SQL statement (it can only translate some expressions - the basics are fine but if your expression calls a C# method, for example, then Entity Framework will probably fail).
So your search layer could have classes that you build up as criteria (eg. a "ContainsName" search class or a "ProductHasId" class) that are then translated into expressions in your search layer. This separates your app entirely from the ORM, which means that ORM details (like the entities or like the limitations of what Funcs can and can't be translated) don't leak out. There's lots out there that's been written about this some of arrangement.
One final note, though, if you are working close to the ORM layer, Entity Framework is very clever and you could probably get a long way without trying to translate your Func<dto, bool> to a Func<entity, bool>. For example, in the below code, accessing "context.Products" returns a "DbSet" and calling Select on it returns an IQueryable and calling Where on that also returns an IQueryable. Entity Framework will translate all of that into a single SQL statement so it won't pull all other Products into memory and then filter the ID on that memory set, it will actually perform the filtering in SQL even though the filter is operating on a projected type (which is equivalent to the DTO in your case) and not the Entity Framework entity -
var results = context.Products
.Select(p => new { ID = p.ProductID, Name = p.ProductName })
.Where(p => p.ID < 10)
.ToList();
The SQL executed is:
SELECT
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName]
FROM [dbo].[Products] AS [Extent1]
WHERE [Extent1].[ProductID] < 10
So, if you changed your code to get something like..
return context.Products
.Map<Product, ProductDTO()>()
.Where(productDtoWherePredicate)
.ToList();
.. then you might be just fine with the Funcs that you already have. I presume that you already have some sort of mapping functions to get from EF entities to DTOs (but if not then you might want to look into AutoMapper to help you out - which has support for "projections", which are basically IQueryable maps).
I am going to put this up as an answer.Thanks to Dan for the quick answer. Looking at what you are saying I can write a query/filter set of classes. for example, take the following code:
GetProducts().GetProductsInCategory().GetProductsWithinPriceRange(minPrice, maxPrice);
This code would run like so: Get Products would get all products in the table and the remaining functions would filter the results. if all queries run like this it may put a significant load on the Data Access Layer/ DB Server Connections... not sure.
or
An Alternate I will work on also is:
If each function creates a Linq expression, I could combine them like this: How do I combine multiple linq queries into one results set?
this may allow me to do this in a manner where I can return the filtered results set from the database.
Either way I am marking this as answered. I will update when I have more details.

Mongodb best way to query

Hi started using mongodb with c#, finding it really cool, just wondering the best way to query
Seem to have an option of the followings
var query = Query<Entity>.EQ(e => e.Id, id);
var entity = collection.FindOne(query);
vs
var entity = collection.Entity.AsQueryable().Single(x => x.Id == id)
Now the second looks more attractive to me as its what Im used to, but in terms of performance and best practice, whats the difference and whats recommended?
Your first example is using the drivers native query - Essentially creating a QueryDocument via the Query<T> helpers etc..
Your second is using Linq.
Under the hood, these both boil down to generating the same query:
db.entity.find({_id: 'abc123'});
The resultant QueryDocument is serialized as the query, in this case
{_id: 'abc123'}
According to the linq docs:
Only LINQ queries that can be translated to an equivalent MongoDB query are supported. If you write a LINQ query that can’t be translated you will get a runtime exception and the error message will indicate which part of the query wasn’t supported.
To me, this would suggest there's some overhead converting LINQ queries into MongoDB queries...
I haven't tested this, but I suspect using Query is slightly more performant
The first approach, in which you build a query and then use it to find a result, is effectively the Specification Pattern.
The second approach, being a direct LINQ query, is typically more familiar to .NET developers.
The specification pattern provides you with a reusable piece of filtering logic. It's very useful if you frequently need to filter collections by the same criteria--and especially if the filter needs to be applied to collections from various repositories.
Here's a quick example of a possible useage of it (pardon any rough code, I've been out of C# for a while now):
static class WidgetSpecification {
function Query<Widget> AvailableWidgets()
{
return new Query<Widget>.EQ(e =>
e.StartDate <= Date.Today
&& e.EndDate >= Date.Today
&& e.Active == true
&& e.InStock == true);
}
}
Then, anywhere in your app that you need "available widgets" you'd call something like:
{
...
var products = getProductsFromSomewhere();
var query = WidgetSpecifiation.AvailableWidgets();
var availableProducts = Products.Find(query);
...
}
If you ever redefine what an "available widget" is you can update the specification and have all consumers behave the same.

Why does this LINQ expression break my loop & conversion logic?

Background
ArticleService is a class that provides methods for front-end layers to facilitate business with the back-end.
Two of its base responsibilities are to convert ViewModels (ArticleViewModel) to the appropriate Models (Article) when persisting data, and the reverse, convert Models to ViewModels when fetching data... so often that I created a private method building ViewModel objects:
private ArticleViewModel BuildViewModel(Article a)
{
return new ArticleViewModel { Title = a.Title /* all properties */ }
}
Moving along, the ArticleService provides a method to fetch all articles from the data store, returning them as ViewModels: public IEnumerable<ArticleViewModel> All()
A calling class uses it like this: var articleViewModels = _articleService.All();
Simple, right?
Problem:
I originally wrote All() lazily with a classic foreach loop:
private IEnumerable<ArticleViewModel> All()
{
var viewModels = new List<ArticleViewModel>();
foreach (var article in _db.Articles)
viewModels.Add(BuildViewModel(article));
return viewModels;
}
It worked fine - articleViewModels was an instantiate list of all view models.
Next, I used ReSharper to convert this loop to a LINQ statement for performance and prettiness, and then combined the assignment statement with the return statement. Result:
private IEnumerable<ArticleViewModel> All()
{
return _db.Articles.Select(article => BuildViewModel(article)).ToList();
}
I debugged the LINQ statement and the beast awakened:
LINQ to Entities does not recognize the method 'ArticleViewModel
BuildViewModel(Article)' and this method cannot be translated into a store expression.
Question - Why does this LINQ statement break my code?
Note: Stepping back to an explicit declaration, assignment, return worked with the LINQ statement, so I'm almost certain it's something to do with the lambda logic.
Question - Why does this LINQ statement break my code?
Because LINQ to Entities is trying to translate BuildViewModel into SQL. It doesn't know how, so it dies miserably.
In your original version, you were streaming the entity from the database to your local box, and then doing the projection using BuildViewModel client-side. That's fine.
so I'm almost certain it's something to do with the lambda logic.
Nope. It's because LINQ to Entities can't translate BuildViewModel into SQL. It doesn't matter if you use a lambda expression to express the projection or not.
You can rewrite the code like this:
return _db.Articles.
.AsEnumerable()
.Select(article => BuildViewModel(article)).ToList();
This causes _db.Articles to be treated as a plain old enumerable, and then does the projection client side. Now LINQ to Entities doesn't have to figure out what to do with BuildViewModel.
The answer by Jason explains the error, but doesn't [didn't] list the simple fix (if you still want to use LINQ). Just add a call to .AsEnumerable() right after "_db.Articles". This will force any future LINQ statements to be performed using LINQ to Objects (in memory) rather than trying to use the IQueryable to perform the statements against the database.
Simply your function BuildViewModel is not traslable to raw SQL. That is.

Linq to SQL Expression Properties That are Translatable to SQL

I have a LINQ to SQL class, we'll call it Test, and I want to be able to access properties with LINQ queries but I get the famed "No Supported Translation to SQL" runtime error. I'm interested in the conceptual problem. Here is my simplified class:
public class Test
{
public int ID {get; set;} // Stored in Database
public int NonForeignKeyValue {get; set;} // Stored in Database
}
Here is sort of an example of what I'm trying to accomplish, but I don't want the overhead of always explicitly writing the join in LINQ:
var db = (new DataContext()).GetTable<Test>();
var q = (from t in db.GetTable<Test>()
join o in db.GetTable<OtherTable>() on o.ID equals t.ID
where t.OtherStuff
select t)
I'd like to be able to add a property to Test that tells me if there are any rows in OtherTable that could be joined with Test:
public bool IsInOtherTable
{
get
{
return (new DataContext())
.GetTable<OtherTabke>()
.Any(x => x.NonForeignKeyValue == this.NonForeignKeyValue));
}
}
Ultimately this is what I want my code to look like, but it errors. I basically want to return all entries that contain some database computed value:
using (DataContext db = new DataContext())
{
var q = db.GetTable<Test>()
.Where(x => x.IsInOtherTable && x.OtherStuff); //Error
}
I'm basically trying to save myself from writing this code every single time I want to check if Test has certain information in another table. I'm not that interested in the exact problem I described, I'm more interested in how to conceptually add the join part to the SQL and still use LINQ. I'm guessing I use Linq.Expression, but I really don't know and I'm not aware of how to do it.
As an aside, I could just write the actual SQL, as its not that complicated, but I'd like to know how to get around this and still use LINQ.
Edit: I tried this property, but I get the same error. Its more complicated that just changing the return type to Expression...
public System.Linq.Expressions.Expression<Func<Article3, bool>> Exists
{
get
{
using (DataContext db = new DataContext())
{
return i => db.GetTable<OtherTable>()
.Any(x => x.NonForeignKeyValue == i.NonForeignKeyValue));
}
}
}
Each time the linq generator is to translate a code into a query, it has to process an expression tree.
In your examples, you are not passing around expression but rather - properties, delegates, i.e. stuff which the expression visitor is unable to "step into".
In general, try to rethink your conditions so that instead of bool you have Expression<T, bool> etc.
http://netpl.blogspot.com/2008/02/linq-to-object-vs-linq-to-sql-and.html
Firstly, I think you may be overestimating "the overhead of always explicitly writing the join in LINQ". It's an extra line of code which has the advantage of being relatively self-documenting as to just what you are doing (always a nice thing), and any other approach is going to be turned first into SQL and then into a query plan that will be at least as expensive to execute, possibly more expensive (SQLServer is good a joins!)
Still, there are two alternatives I can thinkof.
One is to have an EntityRef property on the class that defines this relationship with the other table. You can then test if it is null in your query (or EntitySet if it's on the other side of a one-to-many relationship).
The other is to define a SQL function that returns a bit result indicating whether an id refers to a row that does or doesn't relate to the other table.
Then define a protected method on your DataContext-derived class that matches the signature in C# terms, and has a Function attribute mapping it to that SQL function. (Since this isn't something that you can give a sensible non-db-using version of in the C# version, you can implement the C# function by calling ExecuteMethodCall).
Then you can use that method instead of the join.
Still, this is likely less self-explanatory in the code and at risk of being less efficient than just keeping the join.

LINQ to Entities - Support for Closures (Lambdas)?

I've been working around a problem I have when using LINQ to Entities when using closures.
Apparently, L2E does not support closures. Meaning:
var users = from user in UserRepository.FindAll()
select new UserDTO
{
UserId = user.UserId,
Tickets = from ticket in TicketRepository.FindAll()
where ticket.User == user
select new TicketDTO
{
TicketId = ticket.TicketId
}
};
(NOTE: The "where"-clause is where the problem exists. I am not allowed to compare an entity to another entity because they are not EF primitive types. Only things like Int32, Guid etc. is allowed.)
, is not valid because I cannot compare 'ticket.User' to 'user'
This is simply an example of the problem I have, and I realize that I could compare on the Id, since this a primitive type, as opposed to a closure.
In reality my scenario is alot more complex than this, but this is the scenario I need to solve for now.
A work-around I found online is using a subquery. That DOES work, but for my scenario it's not very effective.
Question:
Do any of you know if:
Entity Framework 4 will support Closures in LINQ to Entities?
There is a better solution to this problem than using sub-queries?
Any additional knowledge you have on this topic will be greatly appreciated!
This is not a problem directly related to closures. The problem is (probably) that you are mixing Entity Framework entities and your data transfer objects. The LINQ provider tries to convert the expression tree of your query into SQL statements and fails because it cannot separate the data transfer objects from the entities and the database, of course, cannot deal with the data transfer objects, too.
I suggest to make the separation much cleaner - at first fetch the data from the database using LINQ to Entity and maybe anonymous types if required, then switch to LINQ to Objects to construct data transfer objects from the retrieved data and all should be fine. Something like the following. (Just to note - I am (safely) assuming the repositories return IQueryable<T>s (else the whole stuff should not work at all).)
var result = UserRepository
.FindAll()
.Select(user => new
{
UserId = user.UserId,
TicketIds = TicketRepository
.FindAll()
.Where(ticket => ticket.User.UserId == user.UserId)
.Select(ticket => ticket.TicketId)
});
Transforming this query result into data transfer objects is now straight forward. Note that the users are compared via the IDs because the Entity Framework does (not yet) support comparisons by reference.
The problem here is that L2E doesn't support reference equality of materialized objects vs. objects in the DB, so you need to compare based on the PK:
var users = from user in UserRepository.FindAll()
select new UserDTO
{
UserId = user.UserId,
Tickets = from ticket in TicketRepository.FindAll()
where ticket.User.UserId == user.UserId
select new TicketDTO
{
TicketId = ticket.TicketId
}
};
(Presuming, here, that the PK of User is called UserId.)

Categories

Resources