EF Core Многие ко многим с одним и тем же классом - PullRequest
0 голосов
/ 28 июня 2018

У меня есть класс City, представляющий город с его почтовым индексом. У меня также есть класс Маршрут, представляющий автобусный маршрут между двумя городами. Итак, я хочу, чтобы в моем классе Route были свойства cityFrom и cityTwo, оба с типом City - отношения многие ко многим с одним и тем же классом.

Как мне сначала добиться этого с помощью кода EF Core?

Thx!

UPDATE:

Мои модели выглядят примерно так:

public class Route
{
    public int Id { get; set; }

    public City CityFrom { get; set; }

    public City CityTo { get; set; }
}  
public class City
{
    public int Id { get; set; }

    public int PostCode { get; set; }

    public string Name { get; set; }
} 

Решит ли это мою проблему:

        modelBuilder.Entity<Route>()
            .HasOne(f => f.CityFrom)
            .WithMany()
            .HasForeignKey(f => f.CityFromId);

        modelBuilder.Entity<Route>()
            .HasOne(f => f.CityTo)
            .WithMany()
            .HasForeignKey(f => f.CityToId);

А также добавить int свойства CityFromId и CityToId в модель Route?

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Я бы не придумал, что это отношение многих ко многим.

Каждый маршрут имеет ровно один FromCity, определенный Foreignkey FromCityId.
Каждый Маршрут имеет ровно один ToCity, определенный иностранным ключом ToCityId.

public class Route
{
    public int Id { get; set; }

    // Every Route has one starting City defined by foreign key:
    public int FromCityId { get; set; }
    public virtual City FromCity { get; set; }

    // Every Route has one termination city, defined by foreign key
    public virtual int ToCityId { get; set; }
    public virtual City ToCity { get; set; }

    ...
}

И DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Proper name for table of Cities
    ModelBuilder.Entity<City>().ToTable("Cities");

    // Every Route has one required starting point defined by foreign key
    // Several routes may use the same City Id
    modelBuilder.Entity<Route>()
        .HasRequired(route => route.FromCity)
        .WithMany()
        .HasForeignKey(route => route.FromCityId)
        .WillCascadeOnDelete(false);

    // Every Route has one required termination point defined by foreign key
    // Several routes may use the same City Id
    modelBuilder.Entity<Route>()
        .HasRequired(route => route.ToCity)
        .WithMany()
        .HasForeignKey(route => route.ToCityId)
        .WillCascadeOnDelete(false);

    base.OnModelCreating(modelBuilder);

Если вы удаляете маршрут, вы не хотите, чтобы его города были удалены, поскольку они могут использоваться другими маршрутами: следовательно, мы не хотим каскадировать при удалении CascadeOnDelete (false)

0 голосов
/ 01 августа 2019

EFCore 3. Нуждается в своем классе «многие ко многим».

Моя проблема была: отношения между людьми (n-> m)

Мое решение. Создайте класс отношений, который реализует многие ко многим. Я выбрал для записей в классе свой собственный идентификатор. Таким образом, класс отношений имеет 1 PK и 2 FK (оба для класса Person).

public class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Relationship> MyRelationships { get; set; }
    public List<Relationship> TheirRelationships { get; set; }
}

// MyRelationships для людей, которых я добавил как отношение. // Их отношения для людей, которые добавили меня в качестве отношения.

public class Relationship {
    public int RelationshipID { get; set; }

    public DateTime Since { get; set; }
    //ref to person myrelationships
    public int MyID { get; set; }
    public Person Me { get; set; }

    //ref to person theirrelationships
    public int TheirID { get; set; }
    public Person They { get; set; }
}

Используя add -igration и update-database, я узнал, что в этом конкретном случае EFCore не может решить, какой FK использовать для какого отношения. Я решил это, используя свободный API.

public class ApplicationDbContext : IdentityDbContext
{

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        //Write Fluent API configurations here

        modelBuilder.Entity<Person>()
            .HasMany<Relationship>(mr => mr.MyRelationships)
            .WithOne(p => p.Me)
            .HasForeignKey(m => m.MyID)
            .OnDelete(DeleteBehavior.NoAction);

        modelBuilder.Entity<Person>()
            .HasMany<Relationship>(tr => tr.TheirRelationships)
            .WithOne(p => p.They)
            .HasForeignKey(t => t.TheirID)
            .OnDelete(DeleteBehavior.NoAction);

    }
    public DbSet<Person> People { get; set; }
    public DbSet<Relationship> Relationships { get; set; }
}

Теперь адд-миграция ххх будет работать:

    protected override void Up(MigrationBuilder migrationBuilder)
    {

        migrationBuilder.CreateTable(
            name: "People",
            columns: table => new
            {
                ID = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                FirstName = table.Column<string>(nullable: true),
                MiddleName = table.Column<string>(nullable: true),
                LastName = table.Column<string>(nullable: true),
                Email = table.Column<string>(nullable: true),
                UserID = table.Column<string>(nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_People", x => x.ID);
                table.ForeignKey(
                    name: "FK_People_AspNetUsers_UserID",
                    column: x => x.UserID,
                    principalTable: "AspNetUsers",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Restrict);
            });

        migrationBuilder.CreateIndex(
            name: "IX_People_UserID",
            table: "People",
            column: "UserID");

        migrationBuilder.CreateTable(
            name: "Relationships",
            columns: table => new
            {
                RelationshipID = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                Since = table.Column<DateTime>(nullable: false),
                Kind = table.Column<int>(nullable: false),
                MyID = table.Column<int>(nullable: false),
                TheirID = table.Column<int>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Relationships", x => x.RelationshipID);
                table.ForeignKey(
                    name: "FK_Relationships_People_MyID",
                    column: x => x.MyID,
                    principalTable: "People",
                    principalColumn: "ID");
                table.ForeignKey(
                    name: "FK_Relationships_People_TheirID",
                    column: x => x.TheirID,
                    principalTable: "People",
                    principalColumn: "ID");
            });

        migrationBuilder.CreateIndex(
            name: "IX_Relationships_MyID",
            table: "Relationships",
            column: "MyID");

        migrationBuilder.CreateIndex(
            name: "IX_Relationships_TheirID",
            table: "Relationships",
            column: "TheirID");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Relationships");

        migrationBuilder.DropTable(
            name: "People");
    }
}
0 голосов
/ 29 июня 2018

Вы можете установить отношения «многие ко многим» в ASP.NET Core, используя Data Annotations

В соответствии с вашими требованиями мы можем ввести новый класс с именем CityRoute, представляющий many-to-many между City и Route

public class Route
{
    public int RouteId { get; set; } // change to make it more specific id
    public string CityFrom { get; set; }
    public string CityTo { get; set; }
    public ICollection<CityRoute> CityRoutes { get; set; }
}  

public class City
{
    public int CityId { get; set; } // change to make it more specific id
    public int PostCode { get; set; }
    public string Name { get; set; }
    public ICollection<CityRoute> CityRoutes { get; set; }
}

// new class
public class CityRoute 
{
    public City City { get; set; }
    public int CityId { get; set; }
    public Route Route { get; set; }
    public int RouteId { get; set; }
}

Ваш DataAnnotations может быть таким

modelBuilder.Entity<CityRoute>()
        .HasKey(cr => new {cr.CityId, cr.RouteId});

Надеюсь, это поможет вам

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...