Как моделировать отношения, которым требуется более одного внешнего ключаC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как моделировать отношения, которым требуется более одного внешнего ключа

Сообщение Anonymous »

Я работаю над библиотекой, предоставляющей интерфейс EntityFramework для баз данных SQLite, созданных программой генеалогии (RootsMagic).
RootsMagic хранит людей и семьи в двух таблицах. Таблица «Семьи» содержит записи для каждой семьи, членом которой является человек в качестве отца или матери (дети моделируются в еще одной таблице). Человек может быть членом ноля, одной или нескольких семей. Записи в таблице «Семьи» содержат хотя бы одного человека (

Код: Выделить всё

FatherId
или MotherID)
Вот сокращенная схема:

Код: Выделить всё

Persons       Families
---------     ----------
INT  Id       INT Id
INT  sex      INT FatherID
TEXT Name     INT MotherID

И вот пример:

Код: Выделить всё

Persons

ID  sex  Name
-------------
1   0    Father1
2   0    Son1
3   1    Grandmother
4   0    Grandfather
5   1    Mother1
6   1    Daughter1
7   1    Mother2
8   1    Daughter2

Families

ID FatherID MotherID
-------------------
1  4        3
2  1        5
3  1        7
  • Семейство 1 моделирует семью Бабушка/Дедушка.
  • Семейство 2 моделирует семью Отец1/Мать1 и
  • Семья 3: вторая семья Отца1 с Матерью2
Чтобы облегчить пользователям доступ к семьям, я бы хотел иметь связь
Семьи в модели Person, в которой перечислены все семьи, членом которых является человек (как отец или мать). В примере должны быть возвращены семьи 2 и 3 для человека 1 (Отец), семья 2 для человека 5 (Мать1) и семья 3 для человека 7 (Мать2).
Это Конечно, несложно получить семьи с помощью запроса типа db.Families.Where(f => f.FatherID == person.Id || f.MotherID == person.Id). Но я бы предпочел прямой доступ из модели Person.
Чтобы обойти эту проблему, я добавил отдельный _familyF (человек является участником как отец) и отдельные отношения _familyM (человек является членом как мать) с человеком через соответствующие внешние ключи FatherID и MotherID в Families. Затем я добавил несопоставленное свойство Families, которое возвращает объединение обоих списков.
Это вроде как работает, но использовать его очень неудобно. Вот соответствующий код:

Код: Выделить всё

using Microsoft.EntityFrameworkCore;

namespace dbexperiment.Models;

public partial class Family
{
public long Id { get; set; }
public long? FatherID { get; set; }
public long? MotherID { get; set; }
public virtual Person Father { get; set; }
public virtual Person Mother { get; set; }
}

public partial class Person
{
public long Id { get; set; }
public string Name { get; set; }
private ICollection _familiesF { get; set; } = new List();
private ICollection _familiesM { get; set; } = new List();
// return a union of both family collections
public ICollection Families => _familiesF.Union(_familiesM).ToList();
}

public class CTX : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)=> optionsBuilder.UseSqlite("test.db");

public DbSet Families { get; set; }
public  DbSet Persons { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(entity =>
{
entity.HasOne(f => f.Father).WithMany("_familiesF").HasForeignKey(f => f.FatherID);
entity.HasOne(f => f.Mother).WithMany("_familiesM").HasForeignKey(f => f.MotherID);
});

modelBuilder.Entity(entity =>
{
entity.Ignore(e => e.Families);
});
}
}
Хотя в принципе это работает, использовать его очень неудобно:

Код: Выделить всё

private static void Main(string[] args)
{
using (var db = new CTX())
{
// var personsWithFamilies = db.Persons.Include(p=>p.Families).Where(p => p.Families.Any()); //  p.Families.Any());

foreach (var person in personsWithFamilies)
{
Console.WriteLine(person.Name);
}
};
}
Есть ли лучшее решение для таких случаев?
Ограничение: поскольку база данных создается сторонней программой, ее не следует изменять.< /п>

Подробнее здесь: https://stackoverflow.com/questions/785 ... oreign-key
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»