代码
我有几个类(class)。
测试.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>();
}
}
节点.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()
{
}
}
测试CFContext.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 对象的引用。保存节点层次结构后,我想在测试中搜索具有特定键和值的节点。
问题
数据存储在数据库中,但是目前我使用测试的 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 无法做到这一点,那么最好的替代方法是什么?
最佳答案
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(在 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();
}
}
}
关于c# - EF代码优先外键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46058649/