【问题标题】:EF Code First Foreign KeysEF 代码优先外键
【发布时间】:2018-02-13 23:11:58
【问题描述】:

代码

我有几节课。

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

属性节点.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 表包含 3 (!) 列引用 Tests 表,其中大多数值为 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 无法做到这一点,那么最好的替代方法是什么?

【问题讨论】:

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


    【解决方案1】:

    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) 您在 (test.cs) 中声明了三种不同的外键关系 Node -> Test (in node.cs)、AttributeNode -> Test 和 LevelNode -> Test。我认为你必须这样建模:

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

    【讨论】:

      猜你喜欢
      • 2018-05-31
      • 1970-01-01
      • 2016-01-31
      • 2014-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-12
      相关资源
      最近更新 更多