Entity Framework односторонняя навигация - PullRequest
0 голосов
/ 20 февраля 2020

У меня есть две таблицы, в которых хранятся детали (FinishedGoods и OePart). Гарантируется, что ни одна запись FinishedGoods и OePart не будет иметь одинаковое значение Id.

Детали (OE или FinishedGoods) могут иметь одно или несколько изображений (см. Схему базы данных внизу).

PartImageLink. PartId может ссылаться на FinishedGoods.Id или OePart.Id.

В Entity Framework (2.1.6) возможно ли иметь свойство навигации из моего объекта C# для FinishedGoods и OePart PartImageLink, но не иметь обратное? В идеале я должен иметь возможность сохранить график FinishedGoods (включая дочерние объекты PartImageLink и Image) и сохранить его для всех дочерних объектов. Возможно ли это вообще?

 CREATE TABLE FinishedGoods (
    Id INT PRIMARY KEY -- unique across all types of parts
 )

 CREATE TABLE OePart (
    Id INT PRIMARY KEY -- unique across all types of parts
 )

 CREATE TABLE PartImageLink (
    Id INT IDENTITY(1,1) PRIMARY KEY,
    PartId int not null, -- a FinishedGoods.Id OR an OePart.Id
    ImageId int not null
 )

 CREATE TABLE Image (
    id INT IDENTITY(1,1) PRIMARY KEY
 )

Если PartImageLink хранит FinishedGoods.Id в столбце PartId, то он не имеет отношения к OePart. Но если PartImageLink сохраняет OePart.Id в столбце PartId, то он не имеет отношения к FinishedGoods.

Ответы [ 2 ]

0 голосов
/ 21 февраля 2020

То, что я в итоге сделал в своей сущности Link (junction), это создание одного свойства для каждого типа части, к которой оно может принадлежать.

public class PartImageLink (
    public int Id { get; set; }
    public int PartId { get; set; }
    public int ImageId { get; set; }

    public virtual OePart OePart { get; set; }
    public virtual FinishedGoods FinishedGoods { get; set; }

    public virtual Image Image { get; set; }
)

public class FinishedGoodsMap
{
    public FinishedGoodsMap(EntityTypeBuilder<FinishedGoods> entity)
    {
        entity.ToTable("FinishedGoods", schema: "dbo");
        entity.HasKey(e => e.Id);

        entity.HasMany(a => a.PartImageLinks).WithOne(b => b.FinishedGoods).HasForeignKey("PartId");
    }
}

public class OePartMap
{
    public OePartMap(EntityTypeBuilder<OePartMap> entity)
    {
        entity.ToTable("OePart", schema: "dbo");
        entity.HasKey(e => e.Id);

        entity.HasMany(a => a.PartImageLinks).WithOne(b => b.OePart).HasForeignKey("PartId");
    }
}

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

0 голосов
/ 20 февраля 2020

Я думаю, что пользовательские объединения должны работать нормально. Я подготовил полный пример, единственное, что я использую хранилище в памяти вместо SQL. Но это будет работать так же. Specifi c две функции отвечают на ваши вопросы

IQueryable<PartImageLinkWithFinishedGoods> GetImageLinkWithFinishedGoods(AppDbContext db, int id)

и

IQueryable<PartImageLinkWithoePart> GetImageLinkWithoeParts(AppDbContext db, int id)

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

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;

namespace ConsoleApp22
{
    // The same models as in the example
    public class FinishedGoods
    {
        [Key]
        public int Id { get; set; }

        [NotMapped]
        public List<PartImageLink> PartImageLinks { get; set; } 
    }

    public class oePart
    {
        [Key]
        public int Id { get; set; }
    }

    public class PartImageLink
    {
        [Key]
        public int Id { get; set; }

        public int PartId { get; set; }
    }

    class AppDbContext : DbContext
    {
        public DbSet<FinishedGoods> FinishedGoods { get; set; }
        public DbSet<oePart> oeParts { get; set; }
        public DbSet<PartImageLink> PartImageLinks { get; set; }

        public AppDbContext(DbContextOptions options) : base(options)
        {
        }

        public override int SaveChanges()
        {
            foreach (var entry in ChangeTracker.Entries().ToList())
            {
                if (entry.Entity.GetType() == typeof(FinishedGoods))
                {
                    var finishedGoods = (FinishedGoods)entry.Entity;

                    if (finishedGoods.PartImageLinks != null)
                    {
                        foreach (var finishedGoodsPartLinks in finishedGoods.PartImageLinks)
                        {
                            Entry(finishedGoodsPartLinks).State = EntityState.Added;
                        }
                    }
                }
            }

            return base.SaveChanges();
        }
    }

    // Custom models to wrap query objects
    class PartImageLinkWithFinishedGoods
    {
        public FinishedGoods FinishedGoods { get; set; }

        public PartImageLink PartImageLink { get; set; }
    }

    class PartImageLinkWithoePart
    {
        public oePart oePart { get; set; }

        public PartImageLink PartImageLink { get; set; }
    }

    class Program
    {
        // Seed data
        private static void AddSomeData(AppDbContext db)
        {

            db.FinishedGoods.Add(new FinishedGoods()
            {
                Id = 1,
            });

            db.oeParts.Add(new oePart()
            {
                Id = 2,
            });

            db.PartImageLinks.Add(new PartImageLink()
            {
                Id = 1,
                PartId = 1,
            });

            db.PartImageLinks.Add(new PartImageLink()
            {
                Id = 2,
                PartId = 2,
            });

            db.FinishedGoods.Add(new FinishedGoods()
            {
                Id = 3,
                PartImageLinks = new List<PartImageLink>()
                {
                    new PartImageLink()
                    {
                        Id = 4,
                        PartId = 3
                    }
                }
            });

            db.SaveChanges();
        }

        // Query your main table and join whatever you expect on PartId field
        static IQueryable<PartImageLinkWithFinishedGoods> GetImageLinkWithFinishedGoods(AppDbContext db, int id)
        {
            return db.PartImageLinks.Where(x => x.Id == id)
                .Join(db.FinishedGoods,
                    x => x.PartId,
                    x => x.Id,
                    (x, y) => new PartImageLinkWithFinishedGoods() { PartImageLink = x, FinishedGoods = y });

        }

        static IQueryable<PartImageLinkWithoePart> GetImageLinkWithoeParts(AppDbContext db, int id)
        {
            return db.PartImageLinks.Where(x => x.Id == id)
                .Join(db.oeParts,
                    x => x.PartId,
                    x => x.Id,
                    (x, y) => new PartImageLinkWithoePart() { PartImageLink = x, oePart = y });

        }

        static void Main(string[] args)
        {
            var options = new DbContextOptionsBuilder().UseInMemoryDatabase("db").Options;
            var db = new AppDbContext(options);

            AddSomeData(db);

            var itemWithFinishedGoods = GetImageLinkWithFinishedGoods(db, 4).FirstOrDefault();
            var itemWithoePart = GetImageLinkWithoeParts(db, 2).FirstOrDefault();
        }

    }
}
...