1

My project is Database First and I'm using Entity Framework 6.2.0.

So I have following classes in simple illustration:

Person [1]    [n] Link_Table [n]    [1] Area
======            ==========            ====
ID                ID                    ID 
                  PersonID (FK)         
                  AreaID (FK)

Now when using following code it will through me an inner exception of "invalid column name 'Area2_ID'".

Db_Context db = new Db_Context();

// getting all links with specific "personID"
List<Link_Table> links = db.Link_Table.Where(item => item.PersonID == personID).ToList();

// now getting all areas
List<Area> areas= new List<Area>();
foreach (Link_Table link in links)
{
    // ERROR
    areas.Add(db.Area.Where(item => item.ID == link.areaID).First());
}

I've already read a little bit about this problem by another users and the problem should be in the (auto-generated) OnModelCreating.

modelBuilder.Entity<Area>()
            .Property(e => e.Description)
            .IsUnicode(false);

        modelBuilder.Entity<Area>()
            .HasOptional(e => e.Area1)
            .WithRequired(e => e.Area2);

For whatever reason using EF in code and creating a new Area-Object, it will show me not only "ID"-Property, but also "Area1"- and "Area2"-Property.

Question How i have to handle it? The columns "Area1_ID" and "Area2_ID" only exist in EF, not in the database. Can I remove these properties or something else to prevent my exception?

EDIT: My models:

[Table("Area")]
public partial class Area
{
    public Guid ID { get; set; }

    [StringLength(40)]
    public string Name { get; set; }

    [Column(TypeName = "text")]
    public string Description{ get; set; }

    public virtual Area Area1 { get; set; }

    public virtual Area Area2 { get; set; }
}

public partial class Link_Table
{
    public Guid ID { get; set; }

    public Guid? Person_ID { get; set; }

    public Guid? Area_ID { get; set; }

    public virtual Person Person{ get; set; }
}

[Table("Person")]
public partial class Person
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Person()
    {
        Link_Table = new HashSet<Link_Table>();
    }

    public Guid ID { get; set; }
}
sandy
  • 464
  • 1
  • 6
  • 13
  • 1
    Can you post your models too? – Neil Jul 05 '18 at 07:20
  • @Neil i did it. – sandy Jul 05 '18 at 07:24
  • `item.ID` is the `Id` of the `Link_Table`, and you are comparing it with the `Id` of the `Person` and The `Area`. You need to compare apples with apples. – Lucian Bumb Jul 05 '18 at 07:25
  • @LucianBumb sorry, tipping mistake. I've corrected it.. – sandy Jul 05 '18 at 07:28
  • @sandy your link table is missing a navigation property to the Area table. It's not required but it might make it easier to find your problem – Neil Jul 05 '18 at 07:29
  • @Neil what do you mean with navigation property? – sandy Jul 05 '18 at 07:31
  • `Link_Table` has a navigation property `Person` with a linked `Person_ID`. `Area_ID` does not have an `Area` navigation property. – Neil Jul 05 '18 at 07:33
  • Can you post the exact exception message? – Neil Jul 05 '18 at 07:49
  • @Neil "Invalid column name 'Area2_ID'.\r\nInvalid column name 'Area2_ID'." – sandy Jul 05 '18 at 07:55
  • I think your database has not been understood correctly by EF and therefore the wrong model has been created. If you create a database from the model, does the new database structure match the original one? If not, then you will have to tweak your EF model until it does. – Neil Jul 05 '18 at 08:18
  • The problem is definitely the two `Area` properties (`Area1` and `Area2`) of your `Area` class. Removing them along with the associated fluent relationship configuration should fix the issue. But your environment and how you get that *auto-generated* is unclear - Database First (edmx) and OnModelCreating are mutually exclusive. – Ivan Stoev Jul 05 '18 at 11:59

3 Answers3

0

This line looks suspect:

areas.Add(db.Area.Where(item => item.ID == link.areaID).First());

item.ID is the index of the link table record, not an area record.

areas.Add(db.Area.Where(item => item.AreaID == link.areaID).First());
Neil
  • 11,059
  • 3
  • 31
  • 56
0

Not very clear for me your goal, but you can refactor your code as follow:

this code:

// now getting all areas
List<Area> areas= new List<Area>();
foreach (Link_Table link in links)
{
    // ERROR
    areas.Add(db.Area.Where(item => item.ID == link.areaID).First());
}

can be replaced with:

var areas=links.Select(link => link.Area).ToList() // if you decide to add a navigation property

or

var areas=db.Areas.Where(area => links?.Any(link=>link.areaID==area.Id)).ToList();

Most problably the error you get was from .First() for the future use .FirstOrDefault()

Please see below an example of code first implementation:

class Program
{
    static void Main(string[] args)
    {
        var db = new ApplicationDbContext();
        var person = new Person();
        IQueryable<Link> personLinks = db.Links.Where(x => x.PersonId == person.Id);
        List<Area> personAreas = personLinks.GroupBy(x => x.Area).Select(x => x.Key).ToList(); 
    }
}

public class Person
{
    public int Id { get; set; }
    public ICollection<Link> Links { get; set; }
}

public class Link
{
    public int Id { get; set; }
    public int PersonId { get; set; }
    public Person Person { get; set; }
    public int AreaId { get; set; }
    public Area Area { get; set; }
}

public class Area
{
    public int Id { get; set; }
    public ICollection<Link> Links { get; set; }
}

public class ApplicationDbContext : DbContext
{
    public DbSet<Person> Persons { get; set; }
    public DbSet<Area> Areas { get; set; }
    public DbSet<Link> Links { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Link>()
            .HasRequired(x => x.Person)
            .WithMany(x => x.Links)
            .HasForeignKey(x => x.PersonId)
            .WillCascadeOnDelete(true);

        modelBuilder.Entity<Link>()
            .HasRequired(x => x.Area)
            .WithMany(x => x.Links)
            .HasForeignKey(x => x.AreaId)
            .WillCascadeOnDelete(false);

        base.OnModelCreating(modelBuilder);
    }
}

here you can lear more about entity framework code first follow this link

Lucian Bumb
  • 2,821
  • 5
  • 26
  • 39
  • The goal is to prevent the exception, because i want to get all areas of one person. I've tried your solutions. But in the first one i don't have the navigation property "[..].Area" and in the second one i got also an exception: "Unable to create a constant value of type Link_Table. Only primitive types ('such as Int32, String, and Guid') are supported in this context." – sandy Jul 05 '18 at 08:03
  • @sandy is difficult for me to understand your code, so I posted an example of how I would do code first, hope will help you. – Lucian Bumb Jul 05 '18 at 08:41
0

When was the last time you ran a database migration? If your model is correct, and your database is saying there are missing fields, then the database doesn't match the code.

Neil
  • 11,059
  • 3
  • 31
  • 56
  • With the database is everything fine. Database existed first and my EF created the model based on my database. I've never changed something. – sandy Jul 05 '18 at 08:07
  • The problem is EF, because it says that the not existing columns Area1_ID and Area2_ID don't exist. And they really don't exists, only in EF! – sandy Jul 05 '18 at 08:08