Reputation: 11177
I have two interfaces for users:
public interface IUserModel
{
int UserId {get;set;}
}
public interface IUserAuthModel : IUserModel
{
string Username {get;set;}
string Password {get;set;}
}
I have user model that implements IUserAuthModel because it requires authorization check for access:
public class UserSubscriptionModel : IUserAuthModel
{
public int UserId {get;set;}
public string Username {get;set;}
public string Password {get;set;}
public bool Subscribed {get;set;}
}
I have user repository based on EF 4.3.1 where I have method for projection:
IQueryable<T> ProjectTo<T>() where T: IUserModel
{
if(typeof(T) == typeof(UserLoginModel)
{
return db.Users.Select(x => new UserSubscriptionModel {
UserId = x.UserId,
Username = x.Username,
Password = x.Password,
Subscribed = x.Subscribed
}) as IQueryable<T>;
}
I have method that retrieves one user based on conditional expression:
T Get<T>(conditionalexpression) where T : IUserModel
{
return ProjectTo<T>.Where(conditionalexpression).FirstOrDefault();
}
I'm implementing authorization method:
public bool Authorize<T>(string username, string password, out T TUser) where T : IUserAuthModel
{
TUser = Get<T>(x => x.Username == username && x.Password == password);
... some other irrelevant code
}
And then I do the following:
UserSubscriptionModel model;
bool authorized = Authorize<UserSubscriptionModel>("hello","world", out model);
This code fails on part where it tries to extract FirstOrDefault. It says Linq to Entities supports casting primitive types.... can't cast from UserSubscriptionModel to IUserAuthModel - or other way around, can't remember. But point is, my generics are not working, even though IUserAuthModel inherits from IUserModel so if my class implements IUserAuthModel it implements IUserModel as well.
What am I missing? I'm not getting a single error/warning and I've made sure my inheritance is done properly (or at least I think so).
I'm sorry if code has some typos, I left real code at work.
Thanks for all the tips.
Upvotes: 1
Views: 664
Reputation: 3209
Entity Framework needs to know that the generic parameter that you're projecting to can be a plain ol' object or struct of some type, otherwise it'll only be able to infer it as an IUserModel
. If you add another type constraint telling it T
will always be one of those things (depending on your domain model; you're probably using classes though):
IQueryable<T> ProjectTo<T>() where T: class, IUserModel
(or this, if all your IUserModel
s are structs:)
IQueryable<T> ProjectTo<T>() where T: struct, IUserModel
that exception should go away.
See these two topics, where I found the answer:
https://stackoverflow.com/a/13701650/183350
https://stackoverflow.com/a/19847671/183350
Upvotes: 2
Reputation: 3153
instead of return as IQueryable try the linq Cast<>
IQueryable<T> ProjectTo<T>() where T: IUserModel
{
if(typeof(T) == typeof(UserLoginModel)
{
return db.Users.Select(x => new UserSubscriptionModel {
UserId = x.UserId,
Username = x.Username,
Password = x.Password,
Subscribed = x.Subscribed
}).Cast<T>;
}
Upvotes: 0