EF Code First外键

时间:2017-09-05 15:30:58

标签: c# entity-framework ef-code-first foreign-keys

代码

我有几堂课。

test.cs中

class Test
{
    public int TestId { get; set; }
    public string Name { get; set; }
    public ICollection<LevelNode> Nodes { get; set; }
    public ICollection<AttributeNode> AttributeNodes { get; set; }

    public Test()
    {
        Nodes = new Collection<LevelNode>();
        AttributeNodes = new Collection<AttributeNode>();
    }
}

Node.cs

abstract class Node
{
    public int NodeId { get; set; }

    public string Key { get; set; }

    public string Value { get; set; }

    public virtual Node ParentNode { get; set; }

    public virtual ICollection<AttributeNode> Attributes { get; set; }

    public Test Test { get; set; }

    public Node()
    {
        Attributes = new Collection<AttributeNode>();
    }
}

LevelNode.cs

class LevelNode : Node
{
    public virtual ICollection<LevelNode> Nodes { get; set; }

    public LevelNode() : base()
    {
        Nodes = new Collection<LevelNode>();
    }
}

AttributeNode.cs

class AttributeNode : Node
{
    public int Source { get; set; }

    public AttributeNode() : base()
    {
    }
}

TestCFContext.cs

class TestCFContext : DbContext
{
    public DbSet<Test> Tests { get; set; }

    public TestCFContext()
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    }
}

主要功能:

static void Main(string[] args)
{
    // Test
    Test t = new Test() { Name = "My Test" };

    // Root & sub
    LevelNode root = new LevelNode() { Key = "root", Test = t };
    LevelNode sub = new LevelNode() { Key = "sub1", Test = t, ParentNode = root };
    root.Nodes.Add(sub);
    t.Nodes.Add(root);

    // Attr1
    AttributeNode attr1 = new AttributeNode() { Key = "Attr1 key", Value = "Attr1 value", Source = 1, Test = t, ParentNode = sub };
    AttributeNode subattr1 = new AttributeNode() { Key = "Subattr1 key", Value = "Subattr1 value", Source = 2, Test = t, ParentNode = attr1 };
    attr1.Attributes.Add(subattr1);
    sub.Attributes.Add(attr1);

    // Attr2
    sub.Attributes.Add(new AttributeNode() { Key = "Attr2 key", Value = "Attr2 value", Source = 3, Test = t, ParentNode = sub });

    // Add to DB
    TestCFContext c = new TestCFContext();
    c.Tests.Add(t);
    c.SaveChanges();

    // Perform search
    IEnumerable<AttributeNode> resultAttributes = t.AttributeNodes.Where(x => x.Key == "Attr2 key" && x.Value == "Attr2 value");
    // => 0 results! :-(
}

目标

我想要完成的事情如下。所有LevelNodes和LevelAttributes(都是来自Node的派生类)都包含对Test对象的引用。保存节点层次结构后,我想用特定的键和值搜索测试中的节点。

问题

数据存储在数据库中,但是当我使用Test的AttributeNodes属性搜索特定属性时,没有找到结果。此外,在数据库中,Nodes表包含引用Tests表的3(!)列,其中大多数值为NULL。

NodeId  Key Value   Source  Discriminator   Node_NodeId ParentNode_NodeId   Test_TestId LevelNode_NodeId    Test_TestId1    Test_TestId2
1   root    NULL    NULL    LevelNode   NULL    NULL    1   NULL    NULL    1
2   sub1    NULL    NULL    LevelNode   NULL    1   1   1   NULL    NULL
3   Attr1 key   Attr1 value 1   AttributeNode   2   2   1   NULL    NULL    NULL
4   Subattr1 key    Subattr1 value  2   AttributeNode   3   3   1   NULL    NULL    NULL
5   Attr2 key   Attr2 value 3   AttributeNode   2   2   1   NULL    NULL    NULL

问题

是否可以简单地在数据库中为Test表提供一个外键,并在使用Test类的Nodes和AttributeNodes属性查询时产生预期结果? 如果使用EF Code First无法做到这一点,那么实现这一目标的最佳替代方法是什么?

1 个答案:

答案 0 :(得分:0)

1)你有一点小错误

IEnumerable<AttributeNode> resultAttributes = t.AttributeNodes.Where(x => x.Key == "Attr2 key" && x.Value == "Attr2 value");

应该是

IEnumerable<AttributeNode> resultAttributes = c.AttributeNodes.Where(x => x.Key == "Attr2 key" && x.Value == "Attr2 value");

2)您已经声明了三种不同的外键关系Node - &gt;测试(在node.cs中),AttributeNode - &gt;测试和LevelNode - &gt;在(test.cs)中进行测试。我认为你必须像这样建模:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace ConsoleApp8
{
    class Test
    {
        public int TestId { get; set; }
        public string Name { get; set; }

        public ICollection<Node> Nodes { get; } = new HashSet<Node>();
        public IEnumerable<LevelNode> LevelNodes
        {
            get
            {
                return Nodes.OfType<LevelNode>(); 
            }
        }

        public IEnumerable<AttributeNode> AttributeNodes
        {
            get
            {
                return Nodes.OfType<AttributeNode>();
            }
        }


    }

    abstract class Node
    {
        public int NodeId { get; set; }

        public string Key { get; set; }

        public string Value { get; set; }

        public virtual Node ParentNode { get; set; }

        public virtual ICollection<AttributeNode> Attributes { get; } = new HashSet<AttributeNode>();

        public Test Test { get; set; }

    }

    class LevelNode : Node
    {
        public virtual ICollection<LevelNode> Nodes { get; } = new HashSet<LevelNode>();

    }

    class AttributeNode : Node
    {
        public int Source { get; set; }

    }
    class TestCFContext : DbContext
    {
        public DbSet<Test> Tests { get; set; }
        public DbSet<LevelNode> LevelNodes { get; set; }

        public DbSet<AttributeNode> AttributeNodes { get; set; }


        public TestCFContext()
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }
    }



    class Program
    {


        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<TestCFContext>());
            // Test
            Test t = new Test() { Name = "My Test" };

            // Root & sub
            LevelNode root = new LevelNode() { Key = "root", Test = t };
            LevelNode sub = new LevelNode() { Key = "sub1", Test = t, ParentNode = root };
            root.Nodes.Add(sub);
            t.Nodes.Add(root);

            // Attr1
            AttributeNode attr1 = new AttributeNode() { Key = "Attr1 key", Value = "Attr1 value", Source = 1, Test = t, ParentNode = sub };
            AttributeNode subattr1 = new AttributeNode() { Key = "Subattr1 key", Value = "Subattr1 value", Source = 2, Test = t, ParentNode = attr1 };
            attr1.Attributes.Add(subattr1);
            sub.Attributes.Add(attr1);

            // Attr2
            sub.Attributes.Add(new AttributeNode() { Key = "Attr2 key", Value = "Attr2 value", Source = 3, Test = t, ParentNode = sub });

            // Add to DB
            using (TestCFContext c = new TestCFContext())
            {
                c.Database.Log = m => Console.WriteLine(m);
                c.Tests.Add(t);
                c.SaveChanges();

            }

            using (TestCFContext c = new TestCFContext())
            {
                c.Database.Log = m => Console.WriteLine(m);
                // Perform search
                IEnumerable<AttributeNode> resultAttributes = c.AttributeNodes.Where(x => x.Key == "Attr2 key" && x.Value == "Attr2 value");
                var numFound = resultAttributes.Count();
                Console.WriteLine($"{numFound} found.");

            }
            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();


        }
    }
}