AnalogWeapon
AnalogWeapon

Reputation: 548

Create a base type for existing Entity Frame work entities (EF Model First)

I'm working with an Entity Framework project that uses the EF Designer and an .edmx file (Model first). The entities map to a MySQL database and the model code is all generated. I have 3 entities that logically represent "resources" and share some, but not all fields. For example:

public partial class ResourceA {
    public int ID { get; set; }
    public long ProductID { get; set; }
    public string Path { get; set; }
}

public partial class ResourceB {
    public int ID { get; set; }
    public long ProductID { get; set; }
    public string Label { get; set; }
}

public partial class ResourceC {
    public int ID { get; set; }
    public long ProductID { get; set; }
    public bool Open { get; set; }
    public bool Replacement { get; set; }
}

Each of those entities maps to a table in the database.

I have an area of code where I want to loop through the three different resource types. In that loop, I have no need to access the properties that aren't common between the 3 entity types. Is there a way I can accomplish this without making three separate loops with all code identical besides the entity types?

I tried to create a GenericResource entity in the EF designer and then make the ResourceX entities inherent it, but I got confused when it came to mapping since I don't need GenericResource to map to anything in the database. I just want to create code that can address any of the three resource types in a read only manner. I don't ever need to create a new GenericResource.

Perhaps this isn't possible with model first and I need to switch to code first?

Upvotes: 1

Views: 575

Answers (2)

Austin T French
Austin T French

Reputation: 5140

I see two approaches: Neither of which I'd call perfect but maybe it will help or an idea to improve upon:

1) Change the database to have a Resource Table, so that ResourceA, B and C can have a foreign key relationship. Each of your classes would then look like:

public partial class ResourceA
    {
        public Resource Resource {get; set;}
        public string Path { get; set; }
    }

and you would have a table that EF would create like:

public partial class Resource
{
  public int ID {get; set;}
  public long ProductId { get; set; }
}

Another option: Being partial classes you can extend the classes and implement them using an interface:

A Quick and slightly dirty proof of concept:

public interface IResources
{
    Resource GetResource();
}

public partial class ResourceA : IResources
{
    public Resource GetResource()
    {
        return new Resource()
        {
            ID = ID,
            ProductID = ProductID
        };
    }


}
public partial class ResourceB : IResources
{
    public Resource GetResource()
    {
        return new Resource()
        {
            ID = ID,
            ProductID = ProductID
        };
    }
}
public partial class ResourceC : IResources
{
    public Resource GetResource()
    {
        return new Resource()
        {
            ID = ID,
            ProductID = ProductID
        };
    }
}
public class Resource
{
    public int ID { get; set; }
    public long ProductID { get; set; }
}

//These are the "generated" EF partials
public partial class ResourceA
{
    public int ID { get; set; }
    public long ProductID { get; set; }
    public string Path { get; set; }
}

public partial class ResourceB
{
    public int ID { get; set; }
    public long ProductID { get; set; }
    public string Label { get; set; }
}

public partial class ResourceC
{
    public int ID { get; set; }
    public long ProductID { get; set; }
    public bool Open { get; set; }
    public bool Replacement { get; set; }
}

This isn't actually in a database for me, so I just mocked it in a console application:

       var A = new ResourceA()
        {
            ID = 15,
            Path = @"C:\Path",
            ProductID = 15001
        };
        var B = new ResourceB()
        {
            ID = 16,
            ProductID = 166101,
            Label = "Ham"
        };
        var C = new ResourceC()
        {
            ID = 188,
            Open = true,
            ProductID = 900014,
            Replacement = false,

        };

        List<IResources> resources = new List<IResources>();
        resources.Add(A);
        resources.Add(B);
        resources.Add(C);

        foreach(var r in resources)
        {
            Console.WriteLine(r.GetResource().ID);
        }

It works, but I'd say it probably isn't ideal. I'd put the Interface and additional classes in a separate file at the Data Access layer so that EF wouldn't overwrite them too.

Upvotes: 1

David Browne - Microsoft
David Browne - Microsoft

Reputation: 89386

You can introduce an interface and add it in a partial class file for each entity. But to have class inheritance, you'd probably have to switch to Code First from an Existing Database. BTW eventually you will probably have to switch to Code First from and Existing Database anyway because it's better, and supported by EF Core.

In Code First if you want the database to be ignorant of a base class, just exclude it from your DbContext. You will be able to substitute instances of the subclasses throughout your code base, but you won't have a single DbSet that you can query over.

Upvotes: 2

Related Questions