简体   繁体   中英

C# Entity Framework Inheritance: Automatic Mapping a Property To Children Property

I was wondering if we can automatically map a property into children property when retrieving from database.

Example:

public class Account
{
    [Key]
    [Index(IsUnique = true)]
    public Guid ID { get; set; } = Guid.NewGuid();

    [Required]
    [Index(IsUnique = true)]
    [StringLength(50)]
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }

    public string Hash { get; set; }

    public ICollection<Role> Roles { get; set; }

    [ForeignKey("AccountProfile")]
    public Guid? AccountProfileId { get; set; }

    public virtual AccountProfile AccountProfile { get; set; }
}

public class AccountProfile
{
    [Key]
    [Index(IsUnique = true)]
    public Guid ID { get; set; } = Guid.NewGuid();

    [Required]
    public string Name { get; set; }

    [Required]
    public string Phone { get; set; }

    public ICollection<AccountAddress> Addresses { get; set; }
}

And then I make a view model:

[NotMapped]
public class AccountVM : Account
{
    public string Name { get; set; } //Map this into AccountProfile.Name
}

I want to auto map the Name into base.AccountProfile.Name when retrieving the data from database:

List<AccountVM> models = db.Accounts.Include(m => m.Roles).Include(m => m.AccountProfile).ToList();

This code will not work because I need to do Select(m => new AccountVM() {...}) which is not code efficient, because I have to assign each of the properties.

So is there a way to do this?


Updated

So I just figurred out a little change in my view model into:

[NotMapped]
public class AccountVM : Account
{
    public string Name { get { return base.AccountProfile.Name; } set { base.AccountProfile.Name = value; } }
}

and my retriever:

List<AccountVM> models = db.Accounts.Include(m => m.Roles).Include(m => m.AccountProfile).Select(m => m as AccountVM).ToList();

Then another error arise:

The 'TypeAs' expression with an input of type 'Yountrep.Models.Account' and a check of type 'Yountrep.ViewModels.AccountVM' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.

I guess the problem is now how to typecast it into AccountVM

Your view model should not be inheriting from an entity model. You can create your view model like this to include any relational objects.

public class AccountVM
{
    public string Name { get; set; }
    public AccountProfile Profile { get; set; }

    public class AccountProfile
    {
        public string Name { get; set; }
    }
}

You can than manually copy over the properties when building your LINQ query:

List<AccountVM> vm = db.Accounts.Select(a => 
{ 
    new AccountVM {
        Name= a.Name,
        Profile = new AccountProfile {
            Name = a.AccountProfile.Name
        }    
    }
}).ToList();

Another alternative is to use AutoMapper. I use AutoMapper for several of my projects, and it reduces the need to have to manually translate every field.

AutoMapper

If you want to flatten properties:

    public class AccountVM
    {
        public string Name { get; set; }
        public string ProfileName { get; set; }
    }

List<AccountVM> vm = db.Accounts.Select(a => 
{ 
    new AccountVM {
        Name= a.Name,
        ProfileName = (a.AccountProfile == null) ? "" : a.AccountProfile.Name
       }    
    }
}).ToList();

I also added a ternary expression to check for null. This will avoid an exception error if profile does not exist.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM