TransWikia.com

EF Core multiple navigation properties to same table with fluent api

Stack Overflow Asked by TheMuyu on July 23, 2020

I searched a lot but no luck to find a solution to my entities.

I have 2 entities. Device & PersonEnterExit
I have 2 Collection of PersonEnterExit in Device entity.
When I run database update it says me you have same entity with different name. do manually name them. how do i do that ? I want to do this with fluent api in onModelCreating.

Devices.cs

using System;
using System.Collections.Generic;

namespace DesTech.Core.Entities
{
    public class Device : BaseEntity
    {
        public bool? IsConnected { get; set; }
        public string Name { get; set; }
        public string Ip { get; set; }
        public int Port { get; set; }
        public DateTime? LastConnectTime { get; set; }
        public DateTime? ChangeClockBatteryWarningTime { get; set; }
        public bool HasFp { get; set; }

        public virtual Location Location { get; set; }
        public virtual ICollection<DeviceOptLog> DeviceOptLog { get; set; }
        public virtual ICollection<DevicePerson> DevicePerson { get; set; }
        public virtual ICollection<DeviceTimeZone> DeviceTimeZone { get; set; }
        public virtual ICollection<PersonEnterExit> PersonEnterExitEnDevice { get; set; }
        public virtual ICollection<PersonEnterExit> PersonEnterExitExDevice { get; set; }
        public virtual ICollection<PersonPassLog> PersonPassLog { get; set; }
    }
}

PersonEnterExit.cs

using System;

namespace DesTech.Core.Entities
{
    public class PersonEnterExit : BaseEntity
    {
        public int Type { get; set; }
        public int? PersonId { get; set; }
        public DateTime? NoEnterTime { get; set; }
        public int? EnDeviceId { get; set; }
        public DateTime? EnVerifyDate { get; set; }
        public string EnPlate { get; set; }
        public int? ExDeviceId { get; set; }
        public DateTime? ExVerifyDate { get; set; }

        public virtual Device EnDevice { get; set; }
        public virtual Device ExDevice { get; set; }
        public virtual Person Person { get; set; }

    }
}

3 Answers

You can use one of these

  1. FluentApi
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Device>()
        .HasMany(a => a.PersonEnterExitEnDevice)
        .WithOne(a => a.EnDevice)
        .HasForeignKey(a => a.EnDeviceId).OnDelete(DeleteBehavior.Restrict); 

    modelBuilder.Entity<Device>()
        .HasMany(a => a.PersonEnterExitExDevice)
        .WithOne(a => a.ExDevice)
        .HasForeignKey(a => a.ExDeviceId).OnDelete(DeleteBehavior.Restrict); 
}
  1. Metadata. you can use InverseProperty to define the relationships.
namespace DesTech.Core.Entities
{
    public class PersonEnterExit : BaseEntity
    {
        public int Type { get; set; }
        public int? PersonId { get; set; }
        public DateTime? NoEnterTime { get; set; }
        public int? EnDeviceId { get; set; }
        public DateTime? EnVerifyDate { get; set; }
        public string EnPlate { get; set; }
        public int? ExDeviceId { get; set; }
        public DateTime? ExVerifyDate { get; set; }
        [InverseProperty("PersonEnterExitEnDevice")]
        public virtual Device EnDevice { get; set; }
        [InverseProperty("PersonEnterExitExDevice")]
        public virtual Device ExDevice { get; set; }
        public virtual Person Person { get; set; }

    }
}
namespace DesTech.Core.Entities
{
    public class Device : BaseEntity
    {
        public bool? IsConnected { get; set; }
        public string Name { get; set; }
        public string Ip { get; set; }
        public int Port { get; set; }
        public DateTime? LastConnectTime { get; set; }
        public DateTime? ChangeClockBatteryWarningTime { get; set; }
        public bool HasFp { get; set; }

        public virtual Location Location { get; set; }
        public virtual ICollection<DeviceOptLog> DeviceOptLog { get; set; }
        public virtual ICollection<DevicePerson> DevicePerson { get; set; }
        public virtual ICollection<DeviceTimeZone> DeviceTimeZone { get; set; }
        [InverseProperty("EnDevice")]
        public virtual ICollection<PersonEnterExit> PersonEnterExitEnDevice { get; set; }
        [InverseProperty("ExDevice")]
        public virtual ICollection<PersonEnterExit> PersonEnterExitExDevice { get; set; }
        public virtual ICollection<PersonPassLog> PersonPassLog { get; set; }
    }
}

Correct answer by Farhad Zamani on July 23, 2020

Okey I combined two answers and its works now. I reply my question for maybe others use same approach. If i mistake please warn me. But it works now.

        builder.HasMany(a => a.PersonEnterExitEnDevice)
            .WithOne(a => a.EnDevice)
            .HasForeignKey(a => a.EnDeviceId)
            .OnDelete(DeleteBehavior.Restrict); 

        builder.HasMany(a => a.PersonEnterExitExDevice)
            .WithOne(a => a.ExDevice)
            .HasForeignKey(a => a.ExDeviceId)
            .OnDelete(DeleteBehavior.Restrict); 


        builder.HasOne(d => d.EnDevice)
            .WithMany(e => e.PersonEnterExitEnDevice)
            .HasForeignKey(d => d.EnDeviceId)
            .HasConstraintName("FK_PersonEnterExit_DeviceEn");

        builder.HasOne(d => d.EnLocation)
            .WithMany(e => e.PersonEnterExitEnLocation)
            .HasForeignKey(d => d.EnLocationId)
            .HasConstraintName("FK_PersonEnterExit_LocationEx");

Answered by TheMuyu on July 23, 2020

Like you mentioned, you need to explicitly configure both relationships. Otherwise, EF will get confused.

build.Entity<PersonEnterExit>()
     .HasOne(e => e.EnDevice)
     .WithMany(d => d.PersonEnterExitEnDevice);

build.Entity<PersonEnterExit>()
     .HasOne(e => e.ExDevice)
     .WithMany(d => d.PersonEnterExitExDevice);

See if this helps. You may need to explicitly configure foreign keys if this doesn't work.

Answered by Tanveer Badar on July 23, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP