ServiceStack / ORM Lite - Foreign Key Relationships

北慕城南 提交于 2019-12-04 15:23:10
mythz

Tables in OrmLite are strictly a 1:1 mapping with the underlying db tables.

This means all complex type properties are blobbed into a db text field with the property name, they're never used to auto-map to child relations as you're expecting to do here.

Here's an early answer that shows how you could map many to many relations with OrmLite.

Try to avoid N+1 queries, remember that every call to Db.x is a remote DB query so you should ideally try to avoid any Database calls in a loop.

Retrieving Posts by Many to Many Table query

You can use OrmLite's support for JOINs to construct a Typed query as you would in normal SQL to query by the Many to Many table and find all posts with the specified Tag:

Create and Populate Posts with Test Data
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 });

Create a SQL Expression Joining all related tables:

When following OrmLite's normal naming conventions above, OrmLite can infer the relationship between each table saving you from specifying the JOIN expression for each query, e.g:

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

Where this Query returns just the first Post for Tag B and both Posts for Tag A.

You can further explore this stand-alone example online by running it Live on Gistlyn.

Populating all Posts with Tags and Comments

If this is a small blog and you want to load all the posts with their related tags and comments e.g. in a home page or RSS feed you can load the entire dataset in memory with 4 queries using Linq2Objects to join them with something like:

//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(),
    };
});

You don't have to include Tags and Comments to the Post entity. In your case your DTO and DB model classes should be different. In Tag and Comment classes you should have PostId property.

In service you should query for Comments where PostId equals your Post Id and do the same for Tags. The results should be added to your Post DTO containing lists of comments and tags.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!