Can't combine "LINQ Join" with other tables - linq

The main problem is that I recieve the following message:
"base {System.SystemException} = {"Unable to create a constant value of type 'BokButik1.Models.Book-Author'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."}"
based on this LinQ code:
IBookRepository myIBookRepository = new BookRepository();
var allBooks = myIBookRepository.HamtaAllaBocker();
IBok_ForfattareRepository myIBok_ForfattareRepository = new Bok_ForfattareRepository();
var Book-Authors =
myIBok_ForfattareRepository.HamtaAllaBok_ForfattareNummer();
var q =
from booknn in allBooks
join Book-Authornn in Book-Authors on booknn.BookID equals
Book-Authornn.BookID
select new { booknn.title, Book-AuthorID };
How shall I solve this problem to get a class instance that contain with property title and Book-AuthorID?
// Fullmetalboy
I also have tried making some dummy by using "allbooks" relation with Code Samples from the address http://www.hookedonlinq.com/JoinOperator.ashx. Unfortunately, still same problem.
I also have taken account to Int32 due to entity framework http://msdn.microsoft.com/en-us/library/bb896317.aspx. Unfortunatley, still same problem.
Using database with 3 tables and one of them is a many to many relationship. This database is used in relation with entity framework
Book-Author
Book-Author (int)
BookID (int)
Forfattare (int)
Book
BookID (int)
title (string)
etc etc etc

It appears that you are using two separate linq-to-sql repositories to join against. This won't work. Joins can only work between tables defined in a single repository.
However, if you are happy to bring all of the data into memory then it is very easy to make your code work. Try this:
var myIBookRepository = new BookRepository();
var myIBok_ForfattareRepository = new Bok_ForfattareRepository();
var allBooks =
myIBookRepository.HamtaAllaBocker().ToArray();
var Book_Authors =
myIBok_ForfattareRepository.HamtaAllaBok_ForfattareNummer().ToArray();
var q =
from booknn in allBooks
join Book_Authornn in Book_Authors
on booknn.BookID equals Book_Authornn.BookID
select new { booknn.title, Book_AuthorID = Book_Authornn.Book_Author };
Note the inclusion of the two .ToArray() calls.
I had to fix some of you variable names and I made a bit of a guess on getting the Author ID.
Does this work for you?
I would suggest only having a single repository and allowing normal joining to occur - loading all objects into memory can be expensive.
If you are making custom repositories you make also consider making a custom method that returns the title and author IDs as a defined class rather than as anonymous classes. Makes for better testability.

Related

LINQ Select from dynamic tableName string

I want to get list of records from an entity model (I'm using EF version 5) with a particular accountID. I'm being supplied with the tableName string (this has to be dynamic) and the accountID. I'm trying the following 2 methods but none of them is working (giving me errors on the IQueryable object 'table':
PropertyInfo info = _db.GetType().GetProperty(tableName);
IQueryable table = info.GetValue(_db, null) as IQueryable;
var query = table.Where(t => t.AccountID == accID)
.Select(t => t);
List <object> recList = ( from records in table
where records.AccountID == accID
select records).ToList<object>();
The var query = table.Where(....).Select(...) is the correct move as it allows reflection for the query builder at runtime. However, t.AccountID is an error because of the type of t remains unknown.
I've previously used a similar approach in LINQ to SQL, using System.Linq.Expressions.Expression, e.g.:
// NOT TESTED
var table=context.GetTable(dynamicTableName);
var theT=table.Experssion; // actually, I forget. DynamicExpression or MemberBinding? or
var theField=Expression.Field(theT, "AccountID"); // or dynamic name
var query=table.Where(Expression.Equal(theField, accID);
var recList=query.ToList<object>();
If your object has a common interface there is a simpler syntax:
IQueryable<MyInterface> table = context.GetTable("table") as IQueryable<MyInterface>;
var recList=from r in table
where table.AccountID == ac // if your AccountID is on MyInterface
select table;
If you only have a few tables to support, you could do this as well:
IQueryable<MyInterface> table;
if("table1"==tableName)
table=_db.table1
elseif("table2"==tableName)
table=_db.table2
elseif("table3"==tableName)
table=_db.table3
else
throw exception
I built a DynamicRepository for a project I am working on. It uses generic methods exposed through EF along with dynamic linq. It might be helpful to look at that source code here:
https://dynamicmvc.codeplex.com/SourceControl/latest#DynamicMVC/DynamicMVC/Data/DynamicRepository.cs
You can query the entity framework metadata workspace to get the type for a given table name. This link might help:
Get Tables and Relationships

Unable to create a constant value of type 'IdentityUserRole'. Only primitive types or enumeration types are supported

In my ASP.NET MVC 5 application I want to list the roles of a user. I downloaded some samples that seem to be broken. Basically I want both the role ID and role name of the roles of a selected user (not the current user!).
ApplicationUser.Roles gives me an IdentityUserRole object with only RoleId and UserId.
ApplicationDbContext.Roles gives me an IdentityRole with RoleId, RoleName etc. of ALL application roles.
So what I want is a result set with the intersection of both sets while retaining full role information so that I can use both its role ID and role name.
I tried Intersect() but that didn't work because both objects are of different type. I tried the dumb style of iterating but got an exception saying the DAta Reader was already active so I am stumped :(
I tried the following on LinQPad (with the appropriate conenctions and namespaces):
string UserName = "user#email.com";
ApplicationDbContext ctx = new ApplicationDbContext();
var allroles = ctx.Roles.OrderBy(r => r.Id);
allroles.Dump(); // dumps well, 6 roles
ApplicationUser user = ctx.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var myroles = user.Roles;
myroles.Dump(); // dumps well, 3 roles
IEnumerable<IdentityRole> list = from roles in allroles
join uroles in myroles
on roles.Id equals uroles.RoleId
select roles;
list.Dump(); // exception
And while the query seems to produce no error during execution, its dumping does regardless of whether I use Dump() or an explicit foreach (IdentityRole item in list). The error I get in this case is
"Unable to reate a constant value of type 'Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole'. Only primitive types or enumeration types are supported in this context".
The only problem here is that you are not calling ToList() method which execute the query immediately (everything will be held in the memory).
For better understanding - ToList() method converts an IEnumerable<T> to a List<T>.
So, your code will look like this:
var allroles = ctx.Roles.OrderBy(r => r.Id).ToList();
var myroles = user.Roles.ToList();
You could use a combination of the two approaches you tried, where you get roles from the context that are present in the ApplicationUser's Roles property...
var roles = ApplicationDbContext.Roles
.Where(ar =>
ApplicationUser.Roles
.Select(ur =>
ur.RoleId)
.Contains(ar.RoleId));
You can do this way :
var rolesList = allroles.ToList().Join(myroles.ToList(),
left => left.Id,
right => right.RoleId,
(left,right) => left);
This way it is working for me for different scenario.
You're trying to join an in-memory list, myroles, with an IQueryable, allroles, which produces a new IQueryable: list. However, this new IQueryable is translated into SQL, so myroles must be translated into SQL as well. This is not supported for lists of non-primitive types.
The solution is to join two IQueryables:
var myroles = ctx.Users.Where(u => u.UserName == UserName).SelectMany(u => u.Roles);
var list = from role in allroles
join urole in myroles
on role.Id equals urole.RoleId
select role;

Selecting an Entity into a property of an object won't populate its related entities despite .Include() being used. Why is this?

I'm using Entity Framework 4.1, and I'm trying to select an entity while also including one of its related collections of entities. This is the standard way of doing this with LINQ. (MacAddressPool is one-to-many with AllowedPartNumbers.)
var query =
from p in MacAddressPools.Include( "AllowedPartNumbers" )
where p.MacAddressPoolID == 2
select p;
var pool = query.FirstOrDefault();
Console.WriteLine( pool.AllowedPartNumbers.IsLoaded );
"True"
Instead, I might want to do this to get other data at the same time:
var query =
from p in MacAddressPools.Include( "AllowedPartNumbers" )
where p.MacAddressPoolID == 2
select new
{
Pool = p,
AssignedMacAddressCount = pool.MacAddressAssignments.Count( a => a.AssignedDate != null )
};
var pool = query.FirstOrDefault().Pool;
Console.WriteLine( pool.AllowedPartNumbers.IsLoaded );
"False"
Why is the related entity collection not loaded this time? It doesn't matter if I use an anonymous type or some class. It won't load the AllowedPartNumbers. The SQL command that is used doesn't even join the AllowedPartNumbers table.
I discovered that I can do this:
var query =
from p in MacAddressPools
where p.MacAddressPoolID == 2
select new
{
Pool = p,
AllowedPartNumbers = p.AllowedPartNumbers,
AssignedMacAddressCount = pool.MacAddressAssignments.Count( a => a.AssignedDate != null )
};
var pool = query.FirstOrDefault().Pool;
Console.WriteLine( pool.AllowedPartNumbers.IsLoaded );
"True"
Even though I'm just going to ignore that AllowedPartNumbers property on my anonymous type, having it there makes LINQ to Entities populate the AllowedPartNumbers property on the pool itself. I don't even need the .Include().
Is there any reason for this strange behavior?
Include() is not guaranteed to work in subqueries and projections. You can find a detailed description of this issue at the MSDN forum and a related post by Shawn Wildermuth: Caution when Eager Loading in the Entity Framework.
Loading related objects is by default set to false, because it may cause a very great performance degradation, think of an object with a collection containing hundreds or thousands of item, what will be happened when you load that object!
Make the lazy loading of entity framework enabled and it will load the related properties upon access(calling the get of property)
context.ContextOptions.LazyLoadingEnabled = true;

LINQ: When to use 'new' in Select clause?

When is it required to use new in the select clause as in the following example? Thanks.
var results = from person in people
select new { FN = person.FirstName, LN = person.LastName };
I've searched and partially understand this: "In the select new, we're creating a new anonymous type with only the properties you need." But does it mean I can omit new and not get an anonymous type?
To restate my question in another way: is 'new' optional? Is 'new' here similar to C# new where it is not required with value type?
Can I do this?
var results = from person in people
select { FN = person.FirstName, LN = person.LastName };
No, new is not optional if you're selecting "new" objects. (which is what you are doing. You are creating new objects of an anonymous type with 2 properties FN and LN)
Simply omitting new is a syntax error.
If you have an existing type you would like to use, (say you've defined a class Person with 2 properties FN and LN) then you can use that type. E.g.
var results = from person in people
select new Person { FN = person.FirstName, LN = person.LastName };
(assuming Person has a parameterless constructor and FN and LN are properties with setters)
The only time you can omit new is if you are not creating a new object, for instance:
var results = from person in people
select LN = person.LastName;
There you are selecting just the LastName and the result is an IEnumerable<string>
If you are projecting to a new type (anonymous class or known class/struct) it is not optional but required.
If you are projecting to an existing instance though of course you don't need the new, i.e. in your example if you just wanted to project to the first name of each person (to get a string enumeration you could just do:
var results = from person in people select person.FirstName
So rule of thumb if you are constructing a new type you need new in the projection (Select), if you are just selecting something that already exists you don't.
Instead of creating an anonymous type you can instantiate an instance of a named type that takes a Person as an argument or assign values using the object initializer syntax.
Example:
var results = from person in people
select new Report(person);
var results = from person in people
select new Report() { Customer = person };
Edit: Or of course just select a single property from the person object as BrokenGlass pointed out!
Edit: I just re-read your question and wanted to point out that anonymous types in C# are just normal types with the type name generated by the compiler. So yes, you still need to use the new operator because you're creating a new instance of a type. Anonymous Types (C# Programming Guide)

ef and linq extension method

I have this sql that i want to have written in linq extension method returning an entity from my edm:
SELECT p.[Id],p.[Firstname],p.[Lastname],prt.[AddressId],prt.[Street],prt.[City]
FROM [Person] p
CROSS APPLY (
SELECT TOP(1) pa.[AddressId],a.[ValidFrom],a.[Street],a.[City]
FROM [Person_Addresses] pa
LEFT OUTER JOIN [Addresses] AS a
ON a.[Id] = pa.[AddressId]
WHERE p.[Id] = pa.[PersonId]
ORDER BY a.[ValidFrom] DESC ) prt
Also could this be re-written in linq extension method using 3 joins?
Assuming you have set the Person_Addresses table up as a pure relation table (i.e., with no data besides the foreign keys) this should do the trick:
var persons = model.People
.Select(p => new { p = p, a = p.Addresses.OrderByDescending(a=>a.ValidFrom).First() })
.Select(p => new { p.p.Id, p.p.Firstname, p.p.LastName, AddressId = p.a.Id, p.a.Street, p.a.City });
The first Select() orders the addresses and picks the latest one, and the second one returns an anonymous type with the properties specified in your query.
If you have more data in your relation table you're gonna have to use joins but this way you're free from them. In my opinion, this is more easy to read.
NOTE: You might get an exception if any entry in Persons have no addresses connected to them, although I haven't tried it out.

Resources