C# 如何在实体框架代码优先方法中映射自身的递归关系
我只想创建基本的递归类别。如果C# 如何在实体框架代码优先方法中映射自身的递归关系,c#,asp.net,asp.net-mvc,entity-framework,asp.net-mvc-4,C#,Asp.net,Asp.net Mvc,Entity Framework,Asp.net Mvc 4,我只想创建基本的递归类别。如果RootCategory\u Id设置为null,则Category为root;如果设置为某个Id,则Category属于其他类别。我在Seed()方法中添加了两个子类别的Category进行测试,但它不起作用。(之后我检查了DB,插入了) 类别模型 我想要达到的目标的图片 这是使用linq到sql的数据库优先方法生成的 延迟加载是打开还是关闭 您可能需要在查询中包含子关系,如下所示 _db.Categories.Include("ChildCategories"
RootCategory\u Id
设置为null,则Category为root;如果设置为某个Id,则Category属于其他类别。我在Seed()
方法中添加了两个子类别的Category进行测试,但它不起作用。(之后我检查了DB,插入了)
类别模型
我想要达到的目标的图片
这是使用linq到sql的数据库优先方法生成的
延迟加载是打开还是关闭 您可能需要在查询中包含子关系,如下所示
_db.Categories.Include("ChildCategories").FirstOrDefault(x => x.ID == 4)
我真的不想在这里用necro线程,但我一直在寻找解决这个确切问题的方法 这是我的解决方案;这有点冗长,但它允许更具可伸缩性的代码优先编程方法。它还引入了允许SoC同时尽可能保持POCO的策略模式 步骤1:创建实体原语和接口。 用户界面:
/// <summary>
/// Represents an entity used with Entity Framework Code First.
/// </summary>
public interface IEntity
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
int Id { get; set; }
}
/// <summary>
/// Represents a recursively hierarchical Entity.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public interface IRecursiveEntity <TEntity> where TEntity : IEntity
{
/// <summary>
/// Gets or sets the parent item.
/// </summary>
/// <value>
/// The parent item.
/// </value>
TEntity Parent { get; set; }
/// <summary>
/// Gets or sets the child items.
/// </summary>
/// <value>
/// The child items.
/// </value>
ICollection<TEntity> Children { get; set; }
}
/// <summary>
/// Acts as a base class for all entities used with Entity Framework Code First.
/// </summary>
public abstract class Entity : IEntity
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; set; }
}
/// <summary>
/// Acts as a base class for all recursively hierarchical entities.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
public abstract class RecursiveEntity<TEntity> : Entity, IRecursiveEntity<TEntity>
where TEntity : RecursiveEntity<TEntity>
{
#region Implementation of IRecursive<TEntity>
/// <summary>
/// Gets or sets the parent item.
/// </summary>
/// <value>
/// The parent item.
/// </value>
public virtual TEntity Parent { get; set; }
/// <summary>
/// Gets or sets the child items.
/// </summary>
/// <value>
/// The child items.
/// </value>
public virtual ICollection<TEntity> Children { get; set; }
#endregion
}
public class Category : RecursiveEntity<Category>
{
/// <summary>
/// Gets or sets the name of the category.
/// </summary>
/// <value>
/// The name of the category.
/// </value>
public string Name { get; set; }
}
/// <summary>
/// Adds functionality to all entities derived from the RecursiveEntity base class.
/// </summary>
public static class RecursiveEntityEx
{
/// <summary>
/// Adds a new child Entity to a parent Entity.
/// </summary>
/// <typeparam name="TEntity">The type of recursive entity to associate with.</typeparam>
/// <param name="parent">The parent.</param>
/// <param name="child">The child.</param>
/// <returns>The parent Entity.</returns>
public static TEntity AddChild<TEntity>(this TEntity parent, TEntity child)
where TEntity : RecursiveEntity<TEntity>
{
child.Parent = parent;
if (parent.Children == null)
parent.Children = new HashSet<TEntity>();
parent.Children.Add(child);
return parent;
}
/// <summary>
/// Adds child Entities to a parent Entity.
/// </summary>
/// <typeparam name="TEntity">The type of recursive entity to associate with.</typeparam>
/// <param name="parent">The parent.</param>
/// <param name="children">The children.</param>
/// <returns>The parent Entity.</returns>
public static TEntity AddChildren<TEntity>(this TEntity parent, IEnumerable<TEntity> children)
where TEntity : RecursiveEntity<TEntity>
{
children.ToList().ForEach(c => parent.AddChild(c));
return parent;
}
}
除了非派生属性之外,我已经从类中剥离了所有内容。Category
从它对RecursiveEntity
类的自关联泛型继承中派生出它的所有其他属性
步骤3:扩展方法(可选)。
为了使整个过程更易于管理,我添加了一些扩展方法,可以轻松地向任何父项添加新的子项。我发现,困难在于,你需要设置一对多关系的两端,而仅仅将孩子添加到列表中并不能让你按照预期的方式处理他们。这是一个简单的修复,从长远来看可以节省大量时间
RecursiveEntityEx静态类:
/// <summary>
/// Represents an entity used with Entity Framework Code First.
/// </summary>
public interface IEntity
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
int Id { get; set; }
}
/// <summary>
/// Represents a recursively hierarchical Entity.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public interface IRecursiveEntity <TEntity> where TEntity : IEntity
{
/// <summary>
/// Gets or sets the parent item.
/// </summary>
/// <value>
/// The parent item.
/// </value>
TEntity Parent { get; set; }
/// <summary>
/// Gets or sets the child items.
/// </summary>
/// <value>
/// The child items.
/// </value>
ICollection<TEntity> Children { get; set; }
}
/// <summary>
/// Acts as a base class for all entities used with Entity Framework Code First.
/// </summary>
public abstract class Entity : IEntity
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; set; }
}
/// <summary>
/// Acts as a base class for all recursively hierarchical entities.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
public abstract class RecursiveEntity<TEntity> : Entity, IRecursiveEntity<TEntity>
where TEntity : RecursiveEntity<TEntity>
{
#region Implementation of IRecursive<TEntity>
/// <summary>
/// Gets or sets the parent item.
/// </summary>
/// <value>
/// The parent item.
/// </value>
public virtual TEntity Parent { get; set; }
/// <summary>
/// Gets or sets the child items.
/// </summary>
/// <value>
/// The child items.
/// </value>
public virtual ICollection<TEntity> Children { get; set; }
#endregion
}
public class Category : RecursiveEntity<Category>
{
/// <summary>
/// Gets or sets the name of the category.
/// </summary>
/// <value>
/// The name of the category.
/// </value>
public string Name { get; set; }
}
/// <summary>
/// Adds functionality to all entities derived from the RecursiveEntity base class.
/// </summary>
public static class RecursiveEntityEx
{
/// <summary>
/// Adds a new child Entity to a parent Entity.
/// </summary>
/// <typeparam name="TEntity">The type of recursive entity to associate with.</typeparam>
/// <param name="parent">The parent.</param>
/// <param name="child">The child.</param>
/// <returns>The parent Entity.</returns>
public static TEntity AddChild<TEntity>(this TEntity parent, TEntity child)
where TEntity : RecursiveEntity<TEntity>
{
child.Parent = parent;
if (parent.Children == null)
parent.Children = new HashSet<TEntity>();
parent.Children.Add(child);
return parent;
}
/// <summary>
/// Adds child Entities to a parent Entity.
/// </summary>
/// <typeparam name="TEntity">The type of recursive entity to associate with.</typeparam>
/// <param name="parent">The parent.</param>
/// <param name="children">The children.</param>
/// <returns>The parent Entity.</returns>
public static TEntity AddChildren<TEntity>(this TEntity parent, IEnumerable<TEntity> children)
where TEntity : RecursiveEntity<TEntity>
{
children.ToList().ForEach(c => parent.AddChild(c));
return parent;
}
}
//
///向从RecursiveEntity基类派生的所有实体添加功能。
///
公共静态类RecursiveEntityEx
{
///
///将新的子实体添加到父实体。
///
///要关联的递归实体的类型。
///父母。
///孩子。
///父实体。
公共静态TEntity AddChild(此TEntity父级,TEntity子级)
其中tenty:RecursiveEntity
{
child.Parent=Parent;
if(parent.Children==null)
parent.Children=newhashset();
parent.Children.Add(child);
返回父母;
}
///
///将子实体添加到父实体。
///
///要关联的递归实体的类型。
///父母。
///孩子们。
///父实体。
公共静态TEntity AddChildren(此TEntity父级,IEnumerable子级)
其中tenty:RecursiveEntity
{
children.ToList().ForEach(c=>parent.AddChild(c));
返回父母;
}
}
一旦你把这些都准备好了,你就可以播种了:
种子方法
/// <summary>
/// Seeds the specified context.
/// </summary>
/// <param name="context">The context.</param>
protected override void Seed(Test.Infrastructure.TestDataContext context)
{
// Generate the root element.
var root = new Category { Name = "First Category" };
// Add a set of children to the root element.
root.AddChildren(new HashSet<Category>
{
new Category { Name = "Second Category" },
new Category { Name = "Third Category" }
});
// Add a single child to the root element.
root.AddChild(new Category { Name = "Fourth Category" });
// Add the root element to the context. Child elements will be saved as well.
context.Categories.AddOrUpdate(cat => cat.Name, root);
// Run the generic seeding method.
base.Seed(context);
}
//
///为指定的上下文设置种子。
///
///上下文。
受保护的覆盖无效种子(Test.Infrastructure.TestDataContext上下文)
{
//生成根元素。
var root=新类别{Name=“First Category”};
//向根元素添加一组子元素。
root.AddChildren(新哈希集)
{
新类别{Name=“第二类别”},
新类别{Name=“第三类别”}
});
//向根元素添加一个子元素。
root.AddChild(新类别{Name=“第四类别”});
//将根元素添加到上下文中。子元素也将被保存。
context.Categories.AddOrUpdate(cat=>cat.Name,root);
//运行泛型种子设定方法。
种子(上下文);
}
堆栈溢出上没有线程坏死。如果有什么值得鼓励的,比如这应该是一个答案和信息的存储库,那么新的信息总是受欢迎的。还有一个注意事项,当使用where tenty:RecursiveEntity
时,它抛出一个编译器错误,说对我来说没有从tenty到ienty的装箱转换或类型参数转换,它给出了警告/信息,而不是错误。蓝色,而不是黄色或红色的VS。有没有一种更优雅的方式来做到这一点,而不打破无休止的铸件干?