Cannot Cast String to GUID in LINQ to Entities - c#

The following code works fine in LinqPad:
(from u in AspNetUsers
let userOrders = (from uo in UserOrders where uo.UserId == new Guid(u.Id) select uo)
select u)
However, when I try to execute the exact same code from my MVC application, it gives me the following error:
var users = (from u in ctx.Users
let userOrders = (from uo in ctx.UserOrders where uo.UserId == new Guid(u.Id) select uo)
select u);
Only parameterless constructors and initializers are supported in LINQ to Entities.
I don't recall ever having any issues converting a string to a GUID in Linq to Entities before. Am I missing some reference?
I have already included all the references I could think of:
using System.Linq;
using System.Data.Entity;
Why does it work in LinqPad but not in MVC?
Edit: Oddly enough, this seems to work:
let userOrders = (from uo in ctx.UserOrders where uo.UserId.ToString() == u.Id select uo)

When you are inside a context the object is not realized yet. Why are you not just using the auto built in navigation properties anyways?
When you have a foreign key in a database or data structure. That creates a 'navigation' property in Entity Framework. As such you can get to child objects a whole lot more quickly. A lot of times they are automatically given depending on your EF options of lazy versus eager loading. The 'include' forces that navigation to be obtained. So if just wanted the orders (seperate table) from my person table I would interrogate person and then get it's child table. I know also there is the concept of 'realized' with Entity Framework and until you can legitimately put something 'ToList' or 'ToString' where if you try to wire things up too much under the hood before they are realized they will not work.
static void Main(string[] args)
{
using (var context = new TesterEntities())
{
var peopleOrders = context.tePerson.Include("teOrder").First(p => p.PersonId == 1).teOrder.ToList();
peopleOrders.ForEach(x => Console.WriteLine($"{x.OrderId} {x.Description}"));
}
}

Ultimately, I just decided to go with the easier approach of casting my GUID .ToString() like so:
let userOrders = (from uo in ctx.UserOrders where uo.UserId.ToString() == u.Id select uo)
The reason being, the default implementation of AspNetUsers defines the column as being varchar, not uniqueidentifier, so in order to change it I would likely have to do something like this How to make EF-Core use a Guid instead of String for its ID/Primary key which I am not presently interested in doing!

Related

EF Core Join from two IQueryables throws System.ArgumentNullException

Having System.ArgumentNullException when trying to Join with ef core from two datasets.
I'm using asp.netcore's built in Identity feature and I have two contexts: MyDbContext and IdentityDbContext. I have a User entity in MyDbContext which holds an IdentityGuid, so I could know which user is associated to which IdentityUser.
I would like to do a Join and get a KeyValuePair and provide that as a ViewModel.
var users = _context.Users;
var identityUsers = _identityContext.Users;
var selection = users.Join(identityUsers,
u => u.IdentityGuid,
iu => iu.Id,
(u, iu) => new KeyValuePair<User, IdentityUser>(u, iu));
return View(await selection.ToListAsync());
Executing that Join throws System.ArgumentNullException, however if I will do a ToList() on both datasets before Join then it works just fine. Here is the Exception:
ArgumentNullException: Value cannot be null.
Parameter name: entityType
Microsoft.EntityFrameworkCore.Utilities.Check.NotNull(T value, string parameterName)
As Miamy mentioned in his comment, EF Core does not support cross-context deferred execution joins. One (or both) of the them will need to have .ToList() called to cause them to both be evaluated and pulled into local memory for the join.
This could also be done in theory by writing the join sql manually and using EF to execute (as this would allow the cross join) but generally the solution should be to pull the data into into local with a .ToList() and then join.
It's an unfortunate thing that cross joins like that arent supported, though I dont believe they are in NHibernate either, so its an all round limitation to my knowledge

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 w/ Entity Framework -- filling objects

I'm not sure if this is possible with the Entity Framework but I'm duplicating too much code filling objects.
Currently my methods do something like:
return (from s in context.some_table
join u in context.user_table on s.user_id equals u.id
where s.id == someId
select new MyObject()
{
TableColumn = s.some_column,
User = new MyUser()
{
Username = u.username,
Id = u.id,
}
}.FirstOrDefault();
I just typed that out as an example. I have a lot of queries where I include info about the user (more than just in that example). So in all of my queries I'm putting that same chunk of code in. If I have 100 methods with that chunk of code and I want to add another column that's returned then I have to update 100 methods. Pain in the butt.
What I'd like to do is have the User object filled by a re-usable method. That way adding/removing columns returned only needs to be changed in one place. Like:
return (from s in context.some_table
join u in context.user_table on s.user_id equals u.id
where s.id = someId
select new MyObject()
{
TableColumn = s.some_column,
User = FillUser(u)
}.FirstOrDefault();
FillUser would be the method. Of course this doesn't work with Entity Framework.
Is there anything I can do at all? I could of course return the whole user table but that's way more info than I need so it's a waste.
I'm using .NET 4.0 if that helps.
Entity framework is ORM tool so its main purpose is to define mapping from database to objects and load entities based on that mapping. Obviously if you need 100 times same user projection it is scenario for either mapped database view, custom defining query or custom query view. You are abusing projections instead of creating reusable mapping.

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.)

Ado.Net Entity : Object doesn't display linked members (foreign keys)

I have a simple databasescheme: User, Account. User has 1-to-many relationship with Account.
I have generated a ado.net entity data model, and I can create users and accounts, and even link them together. In the database the account.user_id is correctly filled, so theoretically I should be able to acces User.Account.ToList() in C# through entity.
However, When I try to acces User.Account.ToList() I get zero results.
User user = db.User.First(U => U.id == 1);
List<Account> accounts = user.Account.ToList(); ##count = 0...
When I add the following code before the previous code it suddenly gives me the correct count 2.
Account account1 = db.Account.First(A => A.id == 1);
Account account2 = db.Account.First(A => A.id == 2);
User user = db.User.First(U => U.id == 1);
List<Account> accounts = user.Account.ToList(); ##count = 2...??
What am I missing here??
You should use the ObjectQuery.Include method for this. Your method works also but results in an additional query.
In your example you would get
User user = db.User.Include("Account").First(u => u.id == 1);
You have to figure out whether the string "Account" is correct. Usually it should be prefixed with something like MyEntities. This depends on the namespace of your entities but with a little trial and error you should be able to figure this out.
Yes, that's a common problem when starting to use the Entity framework - neither parent nor child relationships are lazy loaded so you have to load them explicitly. If you are going to share the object context around between classes / methods you might want to make a check to see if the relationship is already loaded:
e.g.
if(!user.Account.IsLoaded)
user.Account.Load();
You can make this easier with a simple extension method:
public static class EntityExtensions
{
public static void EnsureLoaded(this RelatedEnd relatedEnd)
{
if (!relatedEnd.IsLoaded)
relatedEnd.Load();
}
}
using this makes your load call shorter again:
user.Account.EnsureLoaded();
And as it uses a RelatedEnd, which is common to parent and child relationships in the entity framework, you can use this for parent reference relationships too - e.g.
account.UserReference.EnsureLoaded();
As rwwilden says, if you are always going to load the child objects with the parent in this case, you might want to use an Include to make the call more efficient and avoid an extra roundtrip to the database.
I guess my knowledge is a bit small of the framework. :)
You need to explicitly load the related accounts first.
user.Account.Load();
Now It does display correctly.

Categories

Resources