简体   繁体   中英

Entity Framework - Fluent API - Creating Weird Columns PK : FK FK

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; }
}

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());

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

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.

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