1

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.

Admir Tuzović
  • 10,997
  • 7
  • 35
  • 71
  • How does your code fail when there are no errors/warnings? No data? – Gert Arnold Jun 28 '12 at 21:50
  • Have you tried `IQueryable ProjectTo() where T: IUserModel`. See [covariance and contravariance](http://msdn.microsoft.com/en-us/library/dd799517.aspx). Just a shot. – NinjaNye Jul 17 '13 at 16:25
  • @GertArnold I'm suspecting the OP means they weren't getting any compiler errors/warnings. That would explain the runtime exception. – Paul d'Aoust Jan 09 '15 at 17:31
  • @NinjaNye because the code is compiling correctly, I don't know that leveraging covariance would help in this case, but I'd be eager to hear more of your insights -- running into the same exception myself. – Paul d'Aoust Jan 09 '15 at 17:33
  • @NinjaNye never mind; I found some leads... I'll formulate them into an answer. – Paul d'Aoust Jan 09 '15 at 17:36
  • possible duplicate of [Where is the cast here? LINQ to Entities only supports casting Entity Data Model primitive types](http://stackoverflow.com/questions/13700505/where-is-the-cast-here-linq-to-entities-only-supports-casting-entity-data-model) – Paul d'Aoust Jan 09 '15 at 17:42

2 Answers2

2

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 IUserModels 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

Community
  • 1
  • 1
Paul d'Aoust
  • 3,019
  • 1
  • 25
  • 36
0

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>;
}
Honorable Chow
  • 3,097
  • 3
  • 22
  • 22