Entity Framework - отношение один ко многим - отображение только на один элемент - PullRequest
0 голосов
/ 08 февраля 2019

Мой пример похож на следующий: у меня есть [Table1], который имеет отношение «один ко многим» к [Table2].

Допустим, он выглядит следующим образом:

[Table1]:
    [Id] int

[Table2]:
    [Table1Id] int (foreign key to [Table1])
    [UniqueColumnAtTable2ForGivenTable1Id] int

[Table2] действительно имеет внешний ключ к [Table1], и в [Table2] может быть несколько элементов, имеющих отношение к [Table1].

Я знаю, как определить отображение между [Table1] и[Table2] из кода означает:

public class Table1
{
    public int Id { get; set; }
    public virtual ICollection<Table2> Table2Objects { get; set; }
}
public class Table1_Mapping : EntityTypeConfiguration<Table1>
{
    public class Table1()
    {
        this.HasKey(x => x.Id);
        this.HasMany(x => x.Table2Objects).WithOptional().HasForeignKey(x => x.Table1);
    }
}

Но есть ли способ определить Entity Framework Отображение, где я бы указал отображение Один-ко-многим, но только с отображением в одна конкретная строка из [Table2]?У меня есть [UniqueColumnAtTable2ForGivenTable1Id] столбец в [Table2], который всегда уникален для данного [Table1] - поэтому я знаю, что выполнение чего-то вроде:

SELECT * FROM [Table2] WHERE [Table1Id] = 123 AND [UniqueColumnAtTable2ForGivenTable1Id] = 456

всегда приведет к одномузапрос строки.

Из кода C #, что мне нужно, это что-то вроде:

public class Table1
{
    public int Id { get; set; }
    public virtual ICollection<Table2> Table2Objects { get; set; }
    public virtual Table2 Table2Object456 { get; set; }
}
public class Table1_Mapping : EntityTypeConfiguration<Table1>
{
    public class Table1()
    {
        this.HasKey(x => x.Id);
        this.HasMany(x => x.Table2Objects).WithOptional().HasForeignKey(x => x.Table1);
        this.MagicMethod(x => x.Table2Object456).WithOptional().HasForeignKey(x => x.Table1).OtherMagicMethodWhichAllowsToPutFilter(x => x.UniqueColumnAtTable2ForGivenTable1Id == 456);
    }
}

Конечно, этот фрагмент мне нужен:

this.MagicMethod(x => x.Table2Object456).WithOptional().HasForeignKey(x => x.Table1).OtherMagicMethodWhichAllowsToPutFilter(x => x.UniqueColumnAtTable2ForGivenTable1Id == 456);

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

На мой взгляд, хороший вариант - не делать это, а просто создать метод в репозитории, который обрабатывает этот особый случай:

public class YourRepository
{
    public Table2 Table2WithUniqueColumn456(Table1 table1)
    {
        using var context = new Table1Context();
        return context.Entry(table1)
                      .Collection(t1 => t1.Table2Objects)
                      .Query()
                      .FirstOrDefault(t2 => t2.UniqueColumnAtTable2ForGivenTable1Id == 456);
    }
}

Теперь вы можете явновызывайте этот метод каждый раз, когда вам нужно получить Table2 с этим значением, равным 456.

Если вы запрашиваете любопытство, тогда один вариант bad будет использовать наследование:

public class Table1
{
    public int Id { get; set; }
    public virtual ICollection<Table2> Table2Objects { get; set; }
    public virtual Table2WithUniqueColumn456 Table2Object456 { get; set; }
}

[Table("Table2")]
public class Table2
{
    public int Id { get; set; }
    public int Table1Id { get; set; }
    public int UniqueColumnAtTable2ForGivenTable1Id { get; set; }
}

[Table("Table2")] // this will tell EF to use table-per-hierarchy
public class Table2WithUniqueColumn456 : Table2
{
}

public class Table1_Mapping : EntityTypeConfiguration<Table1>
{
    public class Table1()
    {
        this.HasKey(x => x.Id);
        this.HasMany(x => x.Table2Objects).WithOptional().HasForeignKey(x => x.Table1);
        this.HasOne(x => x.Table2Object456).WithOptional().HasForeignKey(x => x.Table1);
    }
}

Как видите:

  • Вам необходимо обработать логику создания и убедиться, что все объекты с UniqueColumnAtTable2ForGivenTable1Id 456 созданы как Table2WithUniqueColumn456
  • UniqueColumnAtTable2ForGivenTable1Id должен быть неизменным или может привести к более сложной логике редактирования
  • Создает дополнительный столбец в Table2

Возможно, если их не так многоTable2 объектов на Table1, это может быть даже лучше, чем наследование, даже если оно не так эффективно:

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

    public virtual ICollection<Table2> Table2Objects { get; set; }

    [NotMapped]
    public virtual Table2WithUniqueColumn456 Table2Object456 
    {
        get { return Table2Objects.FirstOrDefault(x => x.UniqueColumnAtTable2ForGivenTable1Id == 456; }
    }
}
0 голосов
/ 08 февраля 2019

Просто чтобы иметь представление о том, что вы на самом деле хотите.

Я думаю, вы хотите что-то вроде этого:

public class User {
    public int Id { get; set; }
    public int PrimaryAddressId { get; set;}

    public virtual Address PrimaryAddress { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
}

EF должен автоматически устанавливать связь между PrimaryAddressId и навигационным свойством.

вы на самом деле не хотите использовать эту волшебную конфигурацию ... если вы не хотите всегда иметь тот же адрес, что и у PrimaryAddress, тогда вы можете вместо этого сделать это в качестве значения по умолчанию ... но это, кажется,запах кода и, вероятно, не хотите этого делать?

...