gnychis
gnychis

Reputation: 7555

Difficulty only mapping base class in Entity Framework

I'm having difficulty figuring out how to only map a base class in Entity Framework to my database, while preventing any information about classes that inherit it from being mapped to the database.

I created a simple example to highlight my difficulty where there is a base Worker class, and a child class called Engineer. For some reason, assume that I don't care to store details of the engineer... I only want my database to contain the information in the Worker class.

So I've done the following:

class Program
{
    static void Main(string[] args)
    {
        Engineer e = new Engineer();
        e.Name = "George";
        e.Focus = "Software";

        MyDatabase db = new MyDatabase();
        e.Save(db);
    }
}

public class MyDatabase : DbContext
{
    public DbSet<Worker> Workers { get; set; } 
    public MyDatabase() : base("mytempdb") { }
}

[NotMapped]
public class Engineer : Worker
{
    public string Focus { get; set; }
}


public class Worker
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    public string Name { get; set; }

    public bool Save(MyDatabase db)
    {
        try
        {
            if (db.Workers.Any(w => w.ID == this.ID))
            {
                db.Workers.Attach(this);
                db.Entry(this).State = System.Data.Entity.EntityState.Modified;
            }
            else
            {
                db.Workers.Add((Worker)this);
            }
            db.SaveChanges();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            return false;
        }

        return true;
    }
}

I am doing "Database First" design, and my database table looks like:

CREATE TABLE [dbo].Workers
(
    [ID] INT NOT NULL PRIMARY KEY, 
    [Name] NVARCHAR(200) NULL, 
    [Discriminator] NVARCHAR(200) NULL
)

However, when I run my program, it is still looking for a entity to store Engineer in. I've told it not to map it, hoping that it would only map the base class to the database:

System.InvalidOperationException: Mapping and metadata information could not be found for EntityType 'ConsoleApplication10.Engineer'.

Upvotes: 0

Views: 385

Answers (2)

David Sherret
David Sherret

Reputation: 106820

I think you might have to map the entity to a new Worker entity before saving so that entity framework doesn't look for the object's sub type—Engineer.

For example:

public class Worker
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    public string Name { get; set; }

    public static FromWorker(Worker worker)
    {
        // example of mapping the entity
        return new Worker
        {
            ID = worker.ID,
            Name = worker.Name,
        };
    }

    public bool Save(MyDatabase db)
    {
        try
        {
            Worker worker = Worker.FromWorker(this);

            if (db.Workers.Any(w => w.ID == worker.ID))
            {
                db.Workers.Attach(worker);
                db.Entry(worker).State = System.Data.Entity.EntityState.Modified;
            }
            else
            {
                db.Workers.Add(worker);
            }

            db.SaveChanges();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            return false;
        }

        return true;
    }
}

Upvotes: 1

phil soady
phil soady

Reputation: 11348

EDIT: You already use [NotMapped]
I did not see that first time sorry. So i dont expect it to be in the model.

There is a do not map attribute for properties and equivalent fluent api option for whole classes.

[NotMapped] 
public string BlogCode  { get;set; }

and for a POCO inside the Context

public class MyDbContext : DbContext {
   protected override void OnModelCreating(DbModelBuilder modelBuilder) {

        //Tell EF not to include these in DB. Ignore these please
        // Anthing that EF picks and generates a table for that shoudl not be persisted
       // modelBuilder.Ignore<EFpleaseIgnoreMe>();
        modelBuilder.Ignore<YourType>();
    }
   }

Upvotes: 0

Related Questions