我有一个任务来解析一些网站。解析一些帖子后,我有一个复杂的对象 Post 有很多评论,其中每个评论都有写它的用户和其他评论形式的一些答案。实际上类的结构会更复杂,但是,这里是例子(一些属性被遗漏了,没有必要):
public class Post : IParsedEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public User Author { get; set; }
public IList<Comment> DownLevelComments { get; set; }
public IList<Comment> AllComments { get; set; }
public Post()
{
DownLevelComments = new List<Comment>();
AllComments = new List<Comment>();
}
}
public class User : IParsedEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Name { get; set; }
public string Url { get; set; }
}
public class Comment : IParsedEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public Post Post { get; set; }
public User Author { get; set; }
public Comment ParentComment { get; set; }
public string Text { get; set; }
public IList<Comment> SubComments { get; set; }
public Comment()
{
SubComments = new List<Comment>();
}
}
现在我配置我的数据库上下文:
modelBuilder.Entity<Comment>().HasRequired(c => c.Post).WithMany(c => c.AllComments);
modelBuilder.Entity<Post>().HasMany(c => c.DownLevelComments);
modelBuilder.Entity<Comment>().HasMany<Comment>(c => c.SubComments).WithOptional(c => c.ParentComment);
好的,我已经解析了一篇文章,现在我有一个 Post 实例,其中有很多其他类的实例链接到 post 的主要实例。
第一个问题:现在我有一个项目的多个实例('nsinreal' 有两条评论,所以我有重复的用户实例)。如果我尝试添加 Post 我会捕获异常,因为我有带有重复键的项目。好的,所以我需要编写自己的 TryAdd 方法来尝试添加实体和所有子项;我需要将具有相同主键的实例合并到一个实例;这一切都必须使用 EF 来完成,因为我的代码可以解析不同的帖子,并且同一用户可以出现在不同帖子的评论中。
第二个问题:我不能手动完成,因为它可能需要很多时间。我需要使用反射并使其自动工作。
第三个问题:解析和添加帖子必须在一台机器上使用不同的线程/任务。
目前我有递归函数 TryAdd ,它使步骤:
- 检查该实体尚未在上下文中
- 实体的 Foreach 属性(仅我们的原始 IParsedEntity 类)执行以下操作:
- 从实体中删除它以防止自动插入具有所有属性的所有实体。如果您有重复的用户,例如在帖子中至少出现两次的已解析用户,那就不好了。
- 尝试将属性值添加到数据库上下文并记住答案。必须使用反射魔法来提供泛型方法的正常工作
- 将数据库的答案或属性的原始值推送到特殊字典
- IList 的相同操作
- 将项目添加到上下文
- 恢复当前项目的所有属性和列表
- 仅将本地更改保存到数据库一次
不幸的是,这个算法在不同的线程上有问题。我必须如何重写它?