从POCO对象引用DbContext

时间:2011-04-23 17:04:52

标签: entity-framework c#-4.0 ef-code-first

我正在使用Code First进行下一个项目。我真的很喜欢这个想法,到目前为止,它的效果非常好。我唯一喜欢它的是,我找不到任何关于如何使用这种野兽的文件,谷歌搜索通常指的是现在过时的CTP。

对于这个问题,我将为有向图建模。 图遍历的算法不是最佳的。

我有一个简单的poco结构,就像这样

class Graph : DbContext
{
    public DbSet<Node> Nodes { get; set; }
    public DbSet<Edge> Edges { get; set; }

    public Graph(string connectionString) : base(connectionString) { }
}

class Edge
{
    public int Id { get; set;}
    public double Weight { get; set; }

    public Node StartNode { get; set; }
    public Node EndNode { get; set; }
}

class Node
{
    public int Id { get; set; }
    public string Label { get; set; }
}

简单而整洁。

但现在假设我想向每个节点添加一些对Graph对象的引用,这样节点就可以在图形的上下文中找出自己的内容,例如它有多少边。

我希望我的Node在创建时具有

class Node
{
    public int Id { get; set; }
    public string Label { get; set; }

    //I want this property populated by magic. 
    //Just leaving it here crashes the program
    public Graph Graph { get; set; }

    //So that this property would do meaningful things.
    public int EdgesFromThisNode
    {
        get { return Graph.Edges.Count(e => e.StartNode.Id == Id); }
    }
}

我认为我已经走出惯例来解决我遇到的一个特定问题。例如,可以将此属性作为方法移动到Graph-class。我不想这样做的原因是因为我想绑定到那个属性,绑定是邪恶的。

你们其中一个向导能否引导我选择正确的Annotation / EntityTypeConfiguration魔法组合来拉动这个快速的魔法吗?

我应该注意一个不同的约定吗?例如,如果我能以某种方式绑定所有边缘或更好的边缘,一些边缘(从节点发出的边缘)到节点,那就更优雅了。

提前致谢,如果您对Code First爱好者应该阅读的内容有任何建议......请先分享您的链接!

1 个答案:

答案 0 :(得分:4)

您可以介绍关联的另一面,这意味着从节点开始并以节点结束的边的集合。您不需要Node类中的数据库上下文:

class Edge
{
    public int Id { get; set;}
    public double Weight { get; set; }

    [InverseProperty("OutgoingEdges")]
    [Required]
    public Node StartNode { get; set; }
    [InverseProperty("IncomingEdges")]
    [Required]
    public Node EndNode { get; set; }
}

class Node
{
    public int Id { get; set; }
    public string Label { get; set; }

    public ICollection<Edge> OutgoingEdges { get; set; }
    public ICollection<Edge> IncomingEdges { get; set; }

    public int EdgesFromThisNode
    {
        get { return OutgoingEdges != null ? OutgoingEdges.Count() : 0; }
    }
}

如果您不想要Edge类中的属性:

,请使用Fluent配置
modelBuilder.Entity<Edge>()
            .HasRequired(e => e.StartNode)
            .WithMany(n => n.OutgoingEdges);

modelBuilder.Entity<Edge>()
            .HasRequired(e => e.EndNode)
            .WithMany(n => n.IncomingEdges);

加载Node时,您必须确保加载所需的边集合:

using (var graph = new Graph())
{
    Node node = graph.Nodes.Include(n => n.OutgoingEdges)
                     .FirstOrDefault(n => n.Id == 1);
    // node.EdgesFromThisNode would give now correct result
}

或者,您可以将导航属性标记为virtual,以便从延迟加载中受益。

注意:此解决方案仅在您对节点的传出和传入边缘感兴趣时才有用。 (我主要是提到你问题的这一部分:“如果我能以某种方式绑定所有边缘或更好的边缘,一些边缘(从节点发出的边缘)到节点......”)如果你只想从数据库中加载过多的 number 边缘(所有Edge对象)。

修改

关于EF 4.1的一些资源,特别是Code-First:

代码优先演练:http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-code-first-walkthrough.aspx

关于EF 4.1的12部分教程:http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-1-introduction-and-model.aspx

Morteza Manavi关于代码优先关联和继承的博客:http://weblogs.asp.net/manavi/default.aspx

关于EF 4.1的MSDN网页:http://msdn.microsoft.com/en-us/library/gg696172%28v=vs.103%29.aspx

一些教程视频:http://msdn.microsoft.com/en-us/data/cc300162

修改2

如果你只想将边缘的数字绑定到视图而不加载所有边缘对象,我会考虑使用一个ViewModel来封装Node本身,并且还有一个额外的属性:

public class NodeViewModel
{
    public Node Node { get; set; }
    public int NumberOfOutgoingEdges { get; set; }
}

我会将两个导航集合保留在Node类中(并删除EdgesFromThisNode属性),但我不会为这个特定的绑定方案加载集合,而是使用投影到新的ViewModel类型:< / p>

using (var graph = new Graph())
{
    NodeViewModel nodeViewModel = graph.Nodes
        .Where(n => n.Id == 1)
        .Select(n => new NodeViewModel()
            {
                Node = n,
                NumberOfOutgoingEdges = n.OutgoingEdges.Count()
            })
        .FirstOrDefault();
    // nodeViewModel.Node doesn't have the OutgoingEdges loaded now
}

然后将NodeViewModel绑定到您的视图,而不是直接绑定到Node。这个解决方案避免了以某种方式将数据库上下文注入到模型类中(在我看来,这非常反对POCO的想法)。