简体   繁体   English

实体框架单向导航

[英]Entity Framework One-Way Navigation

I have two tables which store parts (FinishedGoods and OePart).我有两个存储零件的表(FinishedGoods 和 OePart)。 It is guaranteed that no FinishedGoods and OePart record will have the same Id value.保证没有成品和 OePart 记录具有相同的 Id 值。

Parts (OE or FinishedGoods) can have one or more Images (see database schema at bottom).零件(OE 或成品)可以有一个或多个图像(请参阅底部的数据库架构)。

PartImageLink.PartId might refer to a FinishedGoods.Id, or it might refer to OePart.Id. PartImageLink.PartId 可能指的是 FinishedGoods.Id,也可能指的是 OePart.Id。

In Entity Framework (2.1.6) is it possible to have a navigation property from my C# entity for FinishedGoods and OePart to PartImageLink, but not have the reverse?在实体框架 (2.1.6) 中,是否可以将我的 C# 实体的导航属性用于 FinishedGoods 和 OePart 到 PartImageLink,但不能具有相反的属性? Ideally I should be able save a FinishedGoods graph (including child PartImageLink and Image objects) and have it save all children.理想情况下,我应该能够保存一个 FinishedGoods 图(包括子 PartImageLink 和 Image 对象)并让它保存所有孩子。 Is this even possible?这甚至可能吗?

 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
 )

If PartImageLink stores a FinishedGoods.Id in column PartId, then it has no relationship to an OePart.如果 PartImageLink 在 PartId 列中存储了 FinishedGoods.Id,则它与 OePart 没有关系。 But if PartImageLink stores an OePart.Id in column PartId, then it has no relationship to a FinishedGoods.但是,如果 PartImageLink 将 OePart.Id 存储在 PartId 列中,则它与 FinishedGoods 没有关系。

I think custom joins should work fine for you.我认为自定义连接应该适合您。 I've prepared full example, the only thing is that I use in-memory storage instead of SQL.我准备了完整的示例,唯一的问题是我使用内存存储而不是 SQL。 But it will work the same.但它的工作原理是一样的。 Specific two functions answer your questions具体两个函数回答你的问题

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

and

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

Note: static methods are not the best way you can query your db, but it should work as an example for your services注意:静态方法不是查询数据库的最佳方式,但它应该作为您的服务的示例

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();
        }

    }
}

What I ended up doing in my Link (junction) entity is making one property per type of part it could belong too.我最终在我的链接(连接)实体中做的是为它可能属于的每种类型的部件创建一个属性。

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");
    }
}

So my link table ends up with one navigation property per entity it can be linked too, but it allows me to save a single part and images as a graph.所以我的链接表最终为每个实体提供一个导航属性,它也可以链接,但它允许我将单个部分和图像保存为图形。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM