0

I'm trying to set up retrieval from a database. I have an EF (Entity Framework) object emUser and a normal class User that inherits from emUser, but adds some extra functionality.

public class User : emUser
{
    #region Properties
    public string Username
    {
        get { return Email; }
    }
    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }
    #endregion
}

public partial class emUser : EntityObject
{
    [code ...]
}

For some reason, although User inherits from emUser I cannot explicitly convert them. The code I'm using:

List<User> returnUsers = new List<User>();
var users =
    (from u in edm.UserSet.OfType<emUser>()
    select u);

    if (users != null)
    {
        foreach (emUser user in users)
        {
            User newUser = (User)user;
            returnUsers.Add(newUser);
        }
    }
return returnUsers;

I could make User a wrapper for emUser, but then I would have to change it every time I make changes to emUser. I want to use User to differentiate between the classes used in the technical service layer and the domain layer.

I get an error message like this:

{System.InvalidCastException: Unable to cast object of type 'Services.emUser' to type 'Users.User'. at Services.DatabaseController.GetUsers() in [file path]:line 412}

Why can't I convert the emUser to a User?

kumaheiyama
  • 704
  • 1
  • 13
  • 28
  • A `User` is an `emUser`, but an `emUser` is not a `User`. You can't do that. – SLaks Nov 19 '12 at 16:33
  • Why would you expect this downcast to work? EF can only return `EMUser` objects - the ones it knows about. For what it's worth, I think having parallel data structures for the model layer and for the service layer is a bad idea, and a bad use of inheritance. It's not bad design for the service layer to communicate with the layer below it. If you need to add functionality using the model classes that doesn't belong to that layer, do it orthogonally. (Using "regular" functions that take model objects as parameters, or extension methods that are defined at the service layer.) – millimoose Nov 19 '12 at 16:35

2 Answers2

0

Your problem here is what @millimoose said: EF can only return emUser objects, because it doesn't know about User and an emUser might not be a User.

You have three possible solutions from here:

  1. Set up User to inherit from EntityObject, then have emUser inherit from User. This would be a pain to implement and not give you any useful advantages.
  2. Create Data Transfer Objects to pass around, where you basically copy all the properties from an emUser into a User (usually via the User's constructor). This would give you the separation you want, but would be a pain.
  3. Add the extra properties into a new partial class for emUser. This is the one I highly recommend, because it's simple and straightforward.

Here's an example:

// In a manually generated file in the same project
public partial class emUser
{
    #region Properties
    public string Username
    {
        get { return Email; }
    }
    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }
    #endregion
}

// In the automatically generated file
public partial class emUser : EntityObject
{
    [code ...]
}

Usage:

emUser foo = GetUser();
Console.WriteLine("FirstName: " + emUser.FirstName);
Console.WriteLine("FullName: " + emUser.FullName);
Bobson
  • 13,498
  • 5
  • 55
  • 80
  • Thanks! This was very helpful. After giving it some thought, I came up with the same solution (no 3). If I had for instance a common interface I could've used that to map the same properties and so on, but using a partial class is propably the best solution in this case! – kumaheiyama Nov 20 '12 at 07:13
  • @kumaheiyama - Definitely. This is exactly why almost all auto-generated code (whether from EF, L2S, or even just a winform) is generated as a partial class - easy extensibility. Glad to help! – Bobson Nov 20 '12 at 14:46
0

You cannot convert a base class to a derived class unless you add a conversion operator.

public class User : emUser
{
    #region Properties
    public string Username
    {
        get { return Email; }
    }
    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }
    #endregion

    public static explicit operator User (emUser user) 
    {
        User result = new User();
        // set properties
        return result;
    }
}
nerdybeardo
  • 4,655
  • 23
  • 32