ServiceStack/ORM Lite - 外键关系

Cal*_*ass 3 servicestack ormlite-servicestack

我有以下POCO:

[Alias("Posts")]
public class Post : IReturn<Post>
{
    [AutoIncrement]
    [PrimaryKey]
    public int PostId { get; set; }
    public DateTime CreatedDate { get; set; }
    [StringLength(50)]
    public string CreatedBy { get; set; }
    [StringLength(75)]
    public string Title { get; set; }
    public string Body { get; set; }
    public int UpVote { get; set; }
    public int DownVote { get; set; }
    public bool IsPublished { get; set; }

    public List<Comment> Comments { get; set; }
    public List<Tag> Tags { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

它在我CommentTag实体上有一个FK .所以我想从我的服务中回复我的回复,但它说'Invalid Column name 'Comments'''Invalid Column name 'Tags''.如何使用ORM Lite查看哪些评论和标签附加到我的帖子?在EF我只是使用Include来延迟加载我的相关表信息,相当于什么?

编辑

在回答答案时,我已经这样做了:

public class PostFull
{
    public Post Post { get; set; }
    public List<Comment> Comments { get; set; }
    public List<Tag> Tags { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后在我的服务中,我返回这个,我的实体PostTag是一个交集实体,因为我PostTag实体是M:M关系:

var posts = Db.Select<Post>().ToList();
var fullPosts = new List<PostFull>();

posts.ForEach(delegate(Post post)
{
    var postTags = Db.Select<PostTag>(x => x.Where(y => y.PostId == 
    post.PostId)).ToList();

    fullPosts.Add(new PostFull()
    {
        Post = post,
        Tags = Db.Select<Tag>(x => x.Where(y => postTags.Select(z => 
                   z.TagId).Contains(y.TagId))).ToList(),
        Comments = Db.Select<Comment>(x => x.Where(y => y.PostId == 
                       post.PostId)).ToList()
    });
});

return fullPosts;
Run Code Online (Sandbox Code Playgroud)

不确定它是否是一个好的设计模式?

编辑2

这是我的实体:

[Alias("Tags")]
public class Tag
{
    [AutoIncrement]
    [PrimaryKey]
    public int TagId { get; set; }

    [StringLength(50)]
    public string Name { get; set; }
}

[Alias("Posts")]
public class Post
{
    [AutoIncrement]
    [PrimaryKey]
    public int PostId { get; set; }
    public DateTime CreatedDate { get; set; }
    [StringLength(50)]
    public string CreatedBy { get; set; }
    [StringLength(75)]
    public string Title { get; set; }
    public string Body { get; set; }
}

[Alias("PostTags")]
public class PostTag
{
    [AutoIncrement]
    [PrimaryKey]
    public int PostTagId { get; set; }

    [References(typeof(Post))]
    public int PostId { get; set; }

    [References(typeof(Tag))]
    public int TagId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

myt*_*thz 6

OrmLite中的表与底层数据库表严格地是1:1映射.

这意味着所有复杂类型属性都会被填充到带有属性名称的db文本字段中,它们从未用于自动映射到子关系,因为您希望在此处执行此操作.

这是一个早期的答案,展示了如何将多个与OrmLite的关系映射到一起.

尽量避免N + 1个查询,请记住每次调用Db.x都是一个远程数据库查询,因此理想情况下应该尽量避免循环中的任何数据库调用.

通过多对多表查询检索帖子

您可以使用OrmLite对JOIN的支持来构造Typed查询,就像在普通SQL中一样,通过Many to Many表查询并查找具有指定Tag的所有帖子:

使用测试数据创建和填充帖子
db.CreateTable<Post>();
db.CreateTable<Tag>();
db.CreateTable<PostTag>();

var post1Id = db.Insert(new Post { 
    CreatedBy = "gistlyn", Title = "Post 1", Body = "Body 1" }, selectIdentity:true);
var post2Id = db.Insert(new Post { 
    CreatedBy = "gistlyn", Title = "Post 2", Body = "Body 2" }, selectIdentity:true);
db.Insert(new Tag { Id = 1, Name = "A" }, 
          new Tag { Id = 2, Name = "B" });
db.Insert(new PostTag { PostId = post1Id, TagId = 1 }, 
          new PostTag { PostId = post1Id, TagId = 2 });
db.Insert(new PostTag { PostId = post2Id, TagId = 1 });
Run Code Online (Sandbox Code Playgroud)

创建SQL表达式连接所有相关表:

遵循上面的OrmLite的常规命名约定,OrmLite可以推断每个表之间的关系,从而避免为每个查询指定JOIN表达式,例如:

var postsWithTagB = db.Select(db.From<Post>()
                                .Join<PostTag>()
                                .Join<PostTag,Tag>()
                                .Where<Tag>(x => x.Name == "B"));
postsWithTagB.PrintDump();
Run Code Online (Sandbox Code Playgroud)

此查询仅返回标记的第一个帖子和标记的B两个帖子A.

您可以通过在Gistlyn上运行Live来进一步探索这个独立的示例.

用标签和注释填充所有帖子

如果这是一个小博客,并且您想要加载所有帖子及其相关标签和评论,例如在主页或RSS源中,您可以使用Linq2Objects将4个查询加载到内存中的整个数据集以使用以下内容加入它们:

//Only 4 DB calls to read all table data
var posts = Db.Select<Post>();
var postTags = Db.Select<PostTag>();
var tags = Db.Select<Tag>();
var comments = Db.Select<Comment>();

//using Linq2Objects to stitch the data together
var fullPosts = posts.ConvertAll(post =>
{
    var postTagIds = postTags
        .Where(x => x.PostId == post.PostId)
        .Select(x => x.PostTagId).ToList();

    return new PostFull {
        Post = post,
        Tags = tags.Where(x => postTagIds.Contains(x.TagId)).ToList(),
        Comments = comments.Where(x => x.PostId == post.PostId).ToList(),
    };
});
Run Code Online (Sandbox Code Playgroud)

  • 这种方法根本不可扩展,如果数据库中有数千条记录,这种方法就会失败 (4认同)