2

I have an EF 5/MVC 4, database first project I am working on and have created separate edmx files for certain logical functional areas of my application (UserManagement, CompanyManagement, InventoryManagement, OrderManagement). The UserProfile table is in all of the edmx files as it is there to join to the CreatedById and ModifiedById tables so you can get the actual user name. But I don't want to create additional properties and data annotations in each version of the UserProfile table, so I inherit the (what I call) "original version" of UserProfile which is in the UserManagement area which I add my additional properties and add my data annotations. Ok, still with me?

Ok, so here is the original UserProfile class that EF 5 creates (in the UserManagement area/folder):

namespace OTIS.domain.UserMgmt
{
    using System;
    using System.Collections.Generic;

    public partial class UserProfile
    {
        public UserProfile()
        {
            this.webpages_Roles = new HashSet<webpages_Roles>();
        }

        public int UserId { get; set; }
        public Nullable<int> AccountId { get; set; }
        public string UserName { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }

        public virtual webpages_Membership webpages_Membership { get; set; }
        public virtual ICollection<webpages_Roles> webpages_Roles { get; set; }
    }
}

Here is my partial class I use to add additional properties and add the data annotations:

namespace OTIS.domain.UserMgmt
{
    [MetadataType(typeof(UserProfileMD))]
    public partial class UserProfile : IEntity
    {
        public int Id
        {
            get
            {
                return this.UserId;
            }
        }

        public string FullName
        {
            get
            {
                return this.FirstName + " " + this.LastName;
            }
        }

        public string EntityDescription
        {
            get
            {
                return this.FullName;
            }
        }

        public class UserProfileMD
        {
            public int UserId { get; set; }

            [Required]
            [Display(Name = "User Name")]
            public string UserName { get; set; }

            [Required]
            [Display(Name = "First Name")]
            public string FirstName { get; set; }

            [Required]
            [Display(Name = "Last Name")]
            public string LastName { get; set; }

            [Display(Name = "Name")]
            public string FullName { get; set; }

            [Display(Name = "Email")]
            public string Email { get; set; }

        }
    }
}

Now I am working with a version of UserProfile that is in the InventoryMgmt edmx, so I created a partial class of the same name and inherited from the above:

namespace OTIS.domain.InventoryMgmt
{
    [MetadataType(typeof(OTIS.domain.UserMgmt.UserProfile.UserProfileMD))]
    public partial class UserProfileInvnMgmt : UserProfile
    {

    }
}

Now also in the InventoryMgmt edmx is PO Header. Here is the EF generated class (note it references UserProfileInvnMgmt UserProfile which is the foreign key table to CreatedById):

namespace OTIS.domain.InventoryMgmt
{
    using System;
    using System.Collections.Generic;

    public partial class POHeader
    {
        public POHeader()
        {
            this.PODetails = new HashSet<PODetail>();
        }

        public int Id { get; set; }
        public int FacilityId { get; set; }
        public int VendorId { get; set; }
        public int StatusId { get; set; }
        public string Notes { get; set; }
        public int CreatedById { get; set; }
        public System.DateTime CreatedOn { get; set; }
        public int ModifiedById { get; set; }
        public System.DateTime ModifiedOn { get; set; }

        public virtual ICollection<PODetail> PODetails { get; set; }
        public virtual Vendor Vendor { get; set; }
        public virtual POHeaderStatus POHeaderStatus { get; set; }
        public virtual UserProfileInvnMgmt UserProfile { get; set; }
        public virtual UserProfileInvnMgmt UserProfile1 { get; set; }
    }
}

Now I have a method that converts a POHeader class entity to a view model. During design time, it allows me to assign POHeader.UserProfile.FullName to the view model property OrderedBy.

public IEnumerable<POHeadersListViewModel> ConvertClassToViewModel(IEnumerable<POHeader> purchaseOrders)
    {
        IEnumerable<POHeadersListViewModel> poGrid =
            from l in purchaseOrders.ToList()
            select new POHeadersListViewModel()
            {
                Id = l.Id,
                VendorName = l.Vendor.VendorName,
                OrderedBy = l.UserProfile.FullName,
                OrderDate = l.CreatedOn,
                Status = l.POHeaderStatus.DisplayName
                //OwnerName = l.Customer == null ? "" : l.Customer.CustomerName
            };

        return poGrid;
    }

HOWEVER, when you run this code, no value gets assigned to OrderedBy AND if, while debugging, expand out the IEnumerable purchaseOrders variable, you see UserProfile, but if you expand it out, you DO NOT see the FullName property, but FirstName and LastName are populated. The resulting value or OrderBy in the view model is a single space, which seems like the FullName property is being returned, but that FirstName and LastName were null, resulting in FullName just returning the white space that is supposed to separate the FirstName and LastName properties, i.e.

public string FullName
    {
        get
        {
            return this.FirstName + " " + this.LastName;
        }
    }

But note that if I do this:

OrderedBy = l.UserProfile.FirstName + " " + l.UserProfile.LastName,

It works, so FirstName and LastName are not null. Any ideas on why FullName is not be returned correctly? In general, is the best way to to handle the multiple versions of UserProfile?

crichavin
  • 4,672
  • 10
  • 50
  • 95

1 Answers1

0

Not sure this is your issue, but your partial class extends IEntity public partial class UserProfile : IEntity where the auto-gen class does not. I believe these should match exactly, or does C# allow you to do that?

UPDATE I believe you issue is that you are trying the use the derived/calculated property in your linq query, which when you consider mapping this back to your database using EF would not be something it would be able to handle / translate. This discussion seems relevant: Using a partial class property inside LINQ statement

Community
  • 1
  • 1
Matthew
  • 9,851
  • 4
  • 46
  • 77
  • Thanks for the response. It seems like C# allows that. The IEntity interface is working properly in other parts of the code like this. Besides, there is no way the Auto Gen code would put that in. So there must be some other reason. – crichavin Jan 16 '13 at 23:13
  • Have you tried setting a breakpoint and stepping through this to see what is going on? Also, thanks for the update on that. – Matthew Jan 16 '13 at 23:19
  • Yeah, see the part above beginning with "HOWEVER, when you run this code..." – crichavin Jan 17 '13 at 00:27
  • Re-reading and seeing what you were using the derived property for clued me in... see revised answer. – Matthew Jan 17 '13 at 04:08