将相关资源的集合作为具有实体的URL返回

时间:2012-07-15 15:00:29

标签: sqlite rest servicestack

我正在用servicestack编写用户服务,当请求用户资源时,我想以各自的URL形式返回实体集合。资源是所请求用户的朋友。

我当前的用户实体

[RestService("/users")]
[RestService("/users/{Id}")]
[Alias("Users")]
public class User
{
    [AutoIncrement]
    public int      Id              { get; set; }
    public string   Name            { get; set; }
    public string   CellPhoneNumber { get; set; }
    public string   EmailAddress    { get; set; }
    public DateTime CreatedDate     { get; set; }
}

基本上,在我的SQLite数据库中,我会有一个名为“Friendships”的表来表达关系。该表应该像这样工作

ID       PK INT NOT NULL
UserID1  FK INT NOT NULL
UserID2  FK INT NOT NULL

我需要一个“友谊”实体来表达这个吗?如何添加/更改我的用户实体以使ServiceStack将其与友谊集合一起返回?

我认为有可能成为像这样的友谊实体

[RestService("/users/{Id}/friends")]
[Alias("Friendships")]
public class Friendship
{
    [AutoIncrement]
    public int Id      { get; set; }
    public int UserId1 { get; set; }
    public int UserId2 { get; set; }
}

在处理请求时,返回用户朋友的资源URL集合。我不知道如何继续前进,可以使用一些提示/建议。


产生的实施

我最终将我的Friendships表保留在数据库中,但没有实现FriendshipService类,而是使用类似于mythz建议的内容。

[RestService("/users/{Id}/friends")]
public class UserFriends
{
    public int Id { get; set; }
}

正如你所看到的,我保留了mythz'UserFriends实体。我的服务类虽然符合我的需要但有所不同。他/她提出的解决方案没有解决的问题是所讨论的用户实体可以是UserId1或UserId2。这就是我的服务类解决问题的方法。

public class UserFriendsService : RestServiceBase<UserFriends>
{
    public IDbConnectionFactory DbFactory { get; set; }

    public override object OnGet(UserFriends request)
    {
        if (request.Id != default(int))
        {
            User user = DbFactory.Exec(dbCmd => dbCmd.GetById<User>(request.Id));
            var friendIds = DbFactory
                .Exec(dbCmd => dbCmd.Where<Friendship>("UserId1", request.Id).Select(fs => fs.UserId2))
                .Union(DbFactory.Exec(dbCmd => dbCmd.Where<Friendship>("UserId2", request.Id)).Select(fs => fs.UserId1));

            List<User> friends = DbFactory.Exec(dbCmd => dbCmd.GetByIds<User>(friendIds));
            return friends;
        }
        else
        {
            return DbFactory.Exec(dbCmd => dbCmd.Select<User>());
        }
    }
}

我可以通过使用所选的ID并在初始查询中使用dbCmd.GetById<User>()来选择用户实体而不是朋友ID,但我认为这会使代码更复杂且难以阅读。< / p>

1 个答案:

答案 0 :(得分:1)

您应该尝试从外部API隐藏服务的实现细节。在这种情况下,我会为每个朋友返回一个用户DTO列表,例如:

[RestService("/users/{Id}/friends")]
public class UserFriends {
    public Id { get; set; }
}

public class UserFriendsService : ServiceBase<UserFriends> {
    public IDbConnectionFactory DbFactory { get; set; }
    public object Run(UserFriends request) {
        return DbFactory.Exec(dbCmd => dbCmd.Select<User>(
         @"SELECT u.* FROM Users u INNER JOIN Friendships f ON (u.Id = f.UserId2)
           WHERE f.UserId1 = {0}", request.Id));
    }
}

注意:并非适合所有人,但我的首选是将所有ServiceStack响应包装在Typed Response DTO中。这为客户端提供了一致的约定/类型API(即,他们可以预测每个服务的响应),并包括对typed Validation的支持。

public class UserFriendsResponse {
    public List<User> Results { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}