http://www.ox-holdings.com

本文转自,Swift SDK v1.0.0-beta 版发布了

摘要即时通讯云服务商LeanCloud已发布Swift版SDK。以下来自LeanCloud官方消息:今天我们非常高兴地宣布 Swift SDK v1.0.0-beta 版发布了!欢迎 Apple 开发者们使用,为我们提供反馈和建议。版本 v1.0.0-beta 主要支持数据存储、云引擎和短信,兼容 Swift 2 并且开源。部署到云引擎和对服务端的支持会在后续版本中支持。基于 Swift SDK,我们可以很容易地创建数据对象,将其保存到云端。下面举几个例子,大家一看便知。创建一个帖子,并存入云端:let post = LCObject(className: "Post")post.set("title", object: "Hello, Swift!")post.set("content", object: "I love her song.")let result = post.save()查询某个帖子:let query = LCQuery(className: "Post")query.whereKey("title", .MatchedSubstring("Swift"))let result = query.find()注册并创建一个用户:let user = LCUser()user.username = "swift"user.password = "qwert"let result = user.signUp()具体的安装步骤请参考安装指南。如果在使用过程中遇到问题或者有任何建议,可以直接在我们的GitHub 仓库中提交 issue,也可以访问论坛或提交工单来获得支持。访问官网 SDK 专区可以获得更多语言平台的 SDK。

四、内容

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MongoHelper<T> where T : class
{
    public MongoCollection<T> Collection { get; private set; }
 
    public MongoHelper()
    {
        var con = new MongoConnectionStringBuilder(
            ConfigurationManager.ConnectionStrings["MongoDB"].ConnectionString);
 
        var server = MongoServer.Create(con);
        var db = server.GetDatabase(con.DatabaseName);
        Collection = db.GetCollection<T>(typeof(T).Name.ToLower());
    }
}

HAS_ONE through

HAS_ONE through ER

图片 1

An example of using HAS_ONE with through is getting user address where user is bound to address using profile. All these entities (user, profile, and address) do have corresponding models:

class User extends CActiveRecord
{
    ...
    public function relations()
    {
        return array(
            'profile'=>array(self::HAS_ONE,'Profile','user_id'),
            'address'=>array(
                self::HAS_ONE,'Address',array('id'=>'profile_id'),
                    'through'=>'profile'
            ),
        );
    }
}

本章主要讲什么(一句话)?

本章主要讲解:完善博客系统路由功能

图片 2

use xin;
CREATE TABLE bbs_post (
  id int(11) NOT NULL auto_increment,
  title varchar(255) NOT NULL,
  username varchar(255) NOT NULL,
  content varchar(255) NOT NULL,
  threadid int(11) NOT NULL,
  PRIMARY KEY  (id)
);

To submit the comment, I’m going to hijax the form submission and perform the addition using an ajax call. Due to this my action method for adding a comment returns JSON data. Normally if you want to return the rendered HTML for a partial you can use the PartialViewResult, but here if the comment textbox is empty I need to return an error; I can do this easily by rending the AddComment partial again using the invalid comment object as it’s model.

Usage examples

// get address of a user whose ID is 1
$user=User::model()->findByPk(1);
$address=$user->address;

二、技术关健词

Node、MongoDB、Angular2、Mongoose、Route

INSERT INTO bbs_post VALUES (1,'大家了解Ajax技术吗?','ajaxuser','如何学习Ajax技术呢?',1),(2,'通过实例学习应该不错','tom','先看看基础概念,然后多从实例中学习。',1),(3,'谢谢!','max','非常感谢你的建议!',1);

Okay so once it’s installed lets fire up Visual Studio and create a new ASP.NET MVC 3 web project. The first thing we want to do is add a reference to the 10gen C# driver which you can do via nuget. Right click on the libaries folder under the web project and choose Add Libary Package Reference, then search online for ‘mongo’ and add a reference to the offical 10gen driver.

官网中后半段为英文,而且中文的内容比英文少一些,先放到这里,之后有时间再翻译。

4.8、用户注销

代码如下:

/*

说明:本接口用于用户注销。

1.get/:说明是get请求

2.注销用户,即清除服务端的Session

*/

app.get('/get/logout', function(req, res) {

try {

req.session.user = null;

req.session.destroy();  //销毁服务端Session

res.send({ status: 'successed', message: "登出成功!" });

} catch (err) {

res.send({ status: 'failed', message: "出错了,原因如下:" + err });

}

});

 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@model Core.Domain.Post
 
@{
    ViewBag.Title = "Create";
}
 
<h2>Create</h2>
 
@using (Html.BeginForm())
{
    @Html.EditorForModel()
 
    <p>
        <input type="submit" value="Create" />
    </p>
}

我们已经了解了怎样使用 Active Record (AR) 从单个数据表中获取数据。 在本节中,我们讲解怎样使用 AR 连接多个相关数据表并取回关联(join)后的数据集。

五、后述

本章代码下载:

下章剧透:

《项目实战:基于Angular2+Mongodb+Node技术实现的多用户博客系统教程(10)》

                                                  --  完成Node后台加入Session支持及前台跨域访问配置

图片 3

/* 表单元素样式 */
input, textarea {
    border:1px solid black;
}

The only tricky part is that new documents may have been added to the end of the array since the page loaded which could result in duplicate comments being displayed. Let’s say I have 20 comments in my array, and I want the latest documents first, I use -5 for the limit on the initial slice to give me comments 16, 17, 18, 19 and 20. For the next page I’d want to use -5 for skip and -5 for limit to get the next set of 5 comments. This should give me 11, 12, 13, 14 and 15, but what happens if since loading the page somebody else added a comment to the same post? When I go to get the next page there would be 21 comments in total, and my query doing a skip -5 limit -5 would actually return me comments 12, 13, 14, 15 and 16, so comment 16 would be returned twice.

为了使用关系型 AR,我们建议在需要关联的表中定义主键-外键约束。这些约束可以帮助保证相关数据的一致性和完整性。

三、本章涉及核心技术点

图片 4

</body>
</html>

?

Usage examples

// get all students taught by teacher whose ID is 1
$teacher=User::model()->findByPk(1);
$students=$teacher->students;

 

 

4.1、导入相关模块

图片 5

打开routes/index.js 代码,继续完善内容:

var crypto = require('crypto'),

User = require('../models/user.js'),

Post = require('../models/post.js');

settings = require('../settings');

module.exports = function(app) {

。。。。。。

}

图片 6

  1. var crypto = require('crypto')  用于导入将来用来MD5方式加密密码的第三方Node类

  2. User = require('../models/user.js')  导入上一章封装的moongose操作User文档的类

  3. Post = require('../models/post.js');  导入上一章封装的moongose操作Post文档的类

  4. settings = require('../settings');   导入数据库配置的类,后面会用到

4.2、获取博客列表

说明:本接口用于获取博客列表的信息的。

1.get/:说明是get请求

2.如果传递了name参数,则说明是:请求某一个人的博文。如:

3.如果没传递name参数,则说明是请求所有人的博文列表,显示在首页

代码如下:

app.get('/get/post', function(req, res) {

// add at 2016-12-23

var username = null;

if (req.query.name != null) {

username = req.query.name;

} else if (req.session.user != null) {

username = req.session.user.name;

}

//代表查询所有

if (req.query.isAll){

username=null;

}

Post.get(username, function(err, posts) {

if (err) {

posts = [];

}

res.send(posts);

});

});

图片 7

1.  req.query.name ,用于获取get访问的url链结,如:

这里获取到的就是zzz

  1. req.session.user  , 从Session中获取用户信息(PS:这里Session的知识点及配置在下一章讲,这里暂略)

  2. if (req.query.isAll){

username=null;

},即如果传递过来的参数有isAll,则代表查询所有,如:

4.3、请求某个用户的信息

/*

说明:本接口用于获取用户信息的。

1.get:说明是get请求

2.如果传递了name参数,则说明是:请求某个用户的信息。如:

3.如果没传递name参数,则说明是请求所有用户的信息

*/

app.get('/get/user', function(req, res) {

// add at 2016-12-23

var username = null;

if (req.query.name != null) {

username = req.query.name;

}

User.get(username, function(err, users) {

if (err) {

users = [];

}

res.send(users);

});

});

图片 8

User.get(username, function(err, users) {  //调用Model层里的User类get方法查询特定用户信息

if (err) {   //错误处理

users = [];

}

res.send(users);   //回调获取得到的用户集合传递给客户端

});

4.4、用户注册

代码如下:

/*

说明:本接口用于提交注册用户信息的。

1.post/:说明是post请求

2.注册未成功,返回Json格式如下:{status:'failed',message:"xxxxxx!"}

3.注册成功,返回Json格式如下:{status:'success',message:"注册成功!",user:user}

*/

app.post('/post/reg', function(req, res) {

var name = req.body.name,

password = req.body.password,   //注意这是Post方式提交的,不能用req.query.xxx方式获取

password_re = req.body['password_repeat'];

//检验用户两次输入的密码是否一致

if (password_re != password) {

res.send({ status: 'failed', message: "两次输入的密码不一致!" });

return;

}

//生成密码的 md5 值

var md5 = crypto.createHash('md5'),   //对密码采用MD5方式加密

password = md5.update(req.body.password).digest('hex');

var newUser = new User({

name: name,

password: password,

email: req.body.email

});

//检查用户名是否已经存在

User.get(newUser.name, function(err, user) {

if (err) {

res.send({ status: 'error', message: "出错了,原因如下:" + err });

return;

}

if (user) {

res.send({ status: 'failed', message: "用户已存在!" });

return;

}

//如果不存在则新增用户

newUser.save(function(err, user) {

if (err) {

res.send({ status: 'error', message: "出错了,原因如下:" + err });

return;

}

res.send({ status: 'success', message: "注册成功!", user: user });

});

});

});

css文件如下

?

2. 执行关联查询 

执行关联查询最简单的方法是读取一个 AR 实例中的关联属性。如果此属性以前没有被访问过,则一个关联查询将被初始化,它将两个表关联并使用当前 AR 实例的主键过滤。 查询结果将以所关联 AR 类的实例的方式保存到属性中。这就是传说中的 懒惰式加载(lazy loading,也可译为 迟加载) 方式,例如,关联查询只在关联的对象首次被访问时执行。 下面的例子演示了怎样使用这种方式:

// 获取 ID 为 10 的帖子
$post=Post::model()->findByPk(10);
// 获取帖子的作者(author): 此处将执行一个关联查询。
$author=$post->author;

信息: 如果关系中没有相关的实例,则相应的属性将为 null 或一个空数组。 BELONGS_TO 和 HAS_ONE关系的结果是 null, HAS_MANY 和 MANY_MANY 的结果是一个空数组。 注意, HAS_MANY 和MANY_MANY 关系返回对象数组,你需要在访问任何属性之前先遍历这些结果。 否则,你可能会收到 "Trying to get property of non-object(尝试访问非对象的属性)" 错误。

懒惰式加载用起来很方便,但在某些情况下并不高效。如果我们想获取 N 个帖子的作者,使用这种懒惰式加载将会导致执行 N 个关联查询。 这种情况下,我们应该改为使用 渴求式加载(eager loading)方式。

渴求式加载方式会在获取主 AR 实例的同时获取关联的 AR 实例。 这是通过在使用 AR 中的 find 或 findAll 方法时配合使用 with 方法完成的。例如:

$posts=Post::model()->with('author')->findAll();

上述代码将返回一个 Post 实例的数组。与懒惰式加载方式不同,在我们访问每个 Post 实例中的 author 属性之前,它就已经被关联的 User 实例填充了。 渴求式加载通过 一个 关联查询返回所有帖子及其作者,而不是对每个帖子执行一次关联查询。

我们可以在 with() 方法中指定多个关系名字,渴求式加载将一次性全部取回他们。例如,如下代码会将帖子连同其作者和分类一并取回。

$posts=Post::model()->with('author','categories')->findAll();

我们也可以实现嵌套的渴求式加载。像下面这样, 我们传递一个分等级的关系名表达式到 with() 方法,而不是一个关系名列表:

$posts=Post::model()->with(
    'author.profile',
    'author.posts',
    'categories')->findAll();

上述示例将取回所有帖子及其作者和所属分类。它还同时取回每个作者的简介(author.profile)和帖子(author.posts)。

从版本 1.1.0 开始,渴求式加载也可以通过指定 CDbCriteria::with 的属性执行,就像下面这样:

$criteria=new CDbCriteria;
$criteria->with=array(
    'author.profile',
    'author.posts',
    'categories',
);
$posts=Post::model()->findAll($criteria);

或者

$posts=Post::model()->findAll(array(
    'with'=>array(
        'author.profile',
        'author.posts',
        'categories',
    )
);

4.7、提交用户的编写的博文

代码如下:

/*

说明:本接口用于提交用户的编写的博文的。

1.post/:说明是post请求

2.提交未成功,返回Json格式如下:{status:'failed',message:"出错了,原因如下:"+err}

3.提交成功,返回Json格式如下:{status:'successed',message:"保存成功!"}

*/

app.post('/post/post', function(req, res) {

var currentUser = req.session.user,

post = new Post(currentUser.name, req.body.title, req.body.post);

//console.log(post);

post.save(function(err) {

if (err) {

res.send({ status: 'failed', message: "出错了,原因如下:" + err });

} else {

res.send({ status: 'successed', message: "保存成功!" });

}

});

});

//创建新的回帖
function createNewPost(postId) {
    //清空当前表单中各部分信息
    document.getElementById("post_title").value = "";
    document.getElementById("post_content").value = "";
    document.getElementById("username").value = "";

As you can see the TotalComments is added to ViewBag, as well as the number of comments I currently have loaded which I will use for the initial skip value.

9. Relational Query with Named Scopes 

Relational query can also be performed in combination with named scopes. It comes in two forms. In the first form, named scopes are applied to the main model. In the second form, named scopes are applied to the related models.

The following code shows how to apply named scopes to the main model.

$posts=Post::model()->published()->recently()->with('comments')->findAll();

This is very similar to non-relational queries. The only difference is that we have the with() call after the named-scope chain. This query would bring back recently published posts together with their comments.

And the following code shows how to apply named scopes to the related models.

$posts=Post::model()->with('comments:recently:approved')->findAll();
// or since 1.1.7
$posts=Post::model()->with(array(
    'comments'=>array(
        'scopes'=>array('recently','approved')
    ),
))->findAll();
// or since 1.1.7
$posts=Post::model()->findAll(array(
    'with'=>array(
        'comments'=>array(
            'scopes'=>array('recently','approved')
        ),
    ),
));

The above query will bring back all posts together with their approved comments. Note that comments refers to the relation name, while recently and approved refer to two named scopes declared in the Comment model class. The relation name and the named scopes should be separated by colons.

Occasionally you may need to retrieve a scoped relationship using a lazy-loading approach, instead of the normal eager loading method shown above. In that case, the following syntax will do what you need:

~~ [php] // note the repetition of the relationship name, which is necessary $approvedComments = $post->comments('comments:approved'); ~~

Named scopes can also be specified in the with option of the relational rules declared inCActiveRecord::relations(). In the following example, if we access $user->posts, it would bring back allapproved comments of the posts.

class User extends CActiveRecord
{
    public function relations()
    {
        return array(
            'posts'=>array(self::HAS_MANY, 'Post', 'author_id',
                'with'=>'comments:approved'),
        );
    }
}

// or since 1.1.7
class User extends CActiveRecord
{
    public function relations()
    {
        return array(
            'posts'=>array(self::HAS_MANY, 'Post', 'author_id',
                'with'=>array(
                    'comments'=>array(
                        'scopes'=>'approved'
                    ),
                ),
            ),
        );
    }
}

Note: Before 1.1.7 named scopes applied to related models must be specified in CActiveRecord::scopes. As a result, they cannot be parameterized.

Since 1.1.7 it's possible to pass parameters for relational named scopes. For example, if you have scope named rated in the Post that accepts minimum rating of post, you can use it from User the following way:

$users=User::model()->findAll(array(
    'with'=>array(
        'posts'=>array(
            'scopes'=>array(
                'rated'=>5,
            ),
        ),
    ),
));

class Post extends CActiveRecord
{
    ......

    public function rated($rating)
    {
        $this->getDbCriteria()->mergeWith(array(
            'condition'=>'rating=:rating',
            'params'=>array(':rating'=>$rating),
        ));
        return $this;
    }

    ......
}

4.5、用户登录

代码如下(相关代码解释已经写在了代码注释中):

/*

说明:本接口用于提交用户登录信息的。

1.post/:说明是post请求

2.登录未成功,返回Json格式如下:{status:'failed',message:"xxxxxx!"}

3.登录成功,将用户对象保存到Session

4.登录成功,返回Json格式如下:{status:'success',message:"登陆成功!",user:user}

*/

app.post('/post/login', function(req, res) {

//生成密码的 md5 值

var md5 = crypto.createHash('md5'),

password = md5.update(req.body.password).digest('hex');

//检查用户是否存在

User.get(req.body.name, function(err, user) {

if (!user) {

res.send({ status: 'failed', message: "用户不存在!" });

} else if (user.password != password) {

res.send({ status: 'failed', message: "密码错误!" });

} else {

//用户名密码都匹配后,将用户信息存入 session

req.session.user = user;

//console.log(req.session.user);

res.send({ status: 'successed', message: "登陆成功!", user: user });

}

});

});

 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$("form[action$='AddComment']").live("submit", function () {
    $.post(
        $(this).attr("action"),
        $(this).serialize(),
        function (response) {
            if (response.Result == "ok") {
                $(response.CommentHtml).hide().prependTo("#comment-list").fadeIn(1000);
                $("#add-comment").html(response.FormHtml);
                $("#Detail").val("");
            }
            else {
                $("#add-comment").html(response.FormHtml);
            }
        });
    return false;
});

为简单起见,我们使用如下所示的实体-关系(ER)图中的数据结构演示此节中的例子。

一、前言

      上一章主要对项目引入MongoDB进行数据存储,并导入mongoose第三方组件,完成mongodb数据库配置及连结代码及利用面向对象的思想对mongoose组件做了封装。

/* 帖子的样式 */
div.post {
    border-bottom:1px solid black;
    padding:5px;
}

The C# driver also has a class called MongoConnectionStringHelper that you can use to easily get the connection string from your web.config file. I could add my connection string as follows.

信息: 对外键约束的支持在不同的 DBMS 中是不一样的。 SQLite < 3.6.19 不支持外键约束,但你依然可以在建表时声明约束。

4.6、判断用户是否已经登录成功

代码如下:

/*

说明:本接口用于提供给前台,用于判断用户是否已经登录成功了。

1.get/:说明是get请求

2.原理是检查服务端的session.user是否存在(登录成功时保存的)

3.返回true:代表用户已登录

4.返回false,代表用户未登录

*/

app.get('/get/checklogin', function(req, res) {

if (req.session.user) {

res.send({ status: 'successed', message: "已经登录!" ,userName:req.session.user.name});

} else {

res.send({ status: 'failed', message: "没有登录!" ,userName:null});

}

});

/* 提示信息div的样式 */
#statusDiv {
    border:1px solid #999;
    background:#FFFFCC;
    width:100px;
    position:absolute;
    top:50%;
    left:50%;
    margin:-50px 0 0 -100px;
    width:280px;
}

The method is similar to adding a comment but I use Update.Pull which will remove matching documents from the Comments array. Update.Pull allows you to use a mongo query to select the documents to remove, or you can use Update.PullWrapped if you have an instance of the object you want to remove. Im also decrementing the TotalComments field using the Inc method with a negative number.

5. Disambiguating Column Names 

When a column name appears in two or more tables being joined together, it needs to be disambiguated. This is done by prefixing the column name with its table's alias name.

In relational AR query, the alias name for the primary table is fixed as t, while the alias name for a relational table is the same as the corresponding relation name by default. For example, in the following statement, the alias name for Post and Comment is t and comments, respectively:

$posts=Post::model()->with('comments')->findAll();

Now assume both Post and Comment have a column called create_time indicating the creation time of a post or comment, and we would like to fetch posts together with their comments by ordering first the posts' creation time and then the comments' creation time. We need to disambiguate the create_time column like the following:

$posts=Post::model()->with('comments')->findAll(array(
    'order'=>'t.create_time, comments.create_time'
));

Tip: The default alias of a related table is the name of the relation. Please note that if you're using relation from within another relation the alias will be the former relation name only and will not be prefixed with the parent relation. For example, the alias for 'author.group' relation is 'group', not 'author.group'.

$posts=Post::model()->with('author', 'author.group')->findAll(array(
  'order'=>'group.name, author.name, t.title'
));

You can avoid the collision of tables' aliases by specifying the alias property of the relation.

$comments=Comment::model()->with(
  'author',
  'post',
  'post.author'=>array('alias'=>'p_author'))->findAll(array(
  'order'=>'author.name, p_author.name, post.title'
));

<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<link href="bbs.css" type="text/css" rel="stylesheet">
<title>无刷新显示回帖</title>
<script src="bbs.js"></script>
</head>

Here I am using the FindAll method of MongoCollection which returns all documents in the collection. It’s probably not wise to use this method without paging in a production environment as it could be a very expensive query. I am also using the SetFields method which can be used to either include or exlude fields, which is analogous to choosing fields in a SELECT statement in SQL.

7. Relational Query Performance 

As we described above, the eager loading approach is mainly used in the scenario when we need to access many related objects. It generates a big complex SQL statement by joining all needed tables. A big SQL statement is preferrable in many cases since it simplifies filtering based on a column in a related table. It may not be efficient in some cases, however.

Consider an example where we need to find the latest posts together with their comments. Assuming each post has 10 comments, using a single big SQL statement, we will bring back a lot of redundant post data since each post will be repeated for every comment it has. Now let's try another approach: we first query for the latest posts, and then query for their comments. In this new approach, we need to execute two SQL statements. The benefit is that there is no redundancy in the query results.

So which approach is more efficient? There is no absolute answer. Executing a single big SQL statement may be more efficient because it causes less overhead in DBMS for parsing and executing the SQL statements. On the other hand, using the single SQL statement, we end up with more redundant data and thus need more time to read and process them.

For this reason, Yii provides the together query option so that we choose between the two approaches as needed. By default, Yii uses eager loading, i.e., generating a single SQL statement, except when LIMIT is applied to the primary model. We can set the together option in the relation declarations to be true to force a single SQL statement even when LIMIT is used. Setting it to false will result in some of tables will be joined in separate SQL statements. For example, in order to use separate SQL statements to query for the latest posts with their comments, we can declare the comments relation in Post class as follows,

public function relations()
{
    return array(
        'comments' => array(self::HAS_MANY, 'Comment', 'post_id',
                        'together'=>false),
    );
}

We can also dynamically set this option when we perform the eager loading:

$posts = Post::model()->with(
            array('comments'=>array(
                'together'=>false
            ))
        )->findAll();

 代码如下

1
2
3
4
5
6
7
8
9
public void Edit(Post post)
{
    _posts.Collection.Update(
        Query.EQ("_id", post.PostId),
        Update.Set("Title", post.Title)
            .Set("Url", post.Url)
            .Set("Summary", post.Summary)
            .Set("Details", post.Details));
}

Usage examples

// get all groups with all corresponding users
$groups=Group::model()->with('users')->findAll();

// get all groups with all corresponding users and roles
$groups=Group::model()->with('roles','users')->findAll();

// get all users and roles where group ID is 1
$group=Group::model()->findByPk(1);
$users=$group->users;
$roles=$group->roles;

// get all comments where group ID is 1
$group=Group::model()->findByPk(1);
$comments=$group->comments;

    var postDiv = createDiv("post", "");    //创建回帖的外层div
    postDiv.id = "post" + postId;           //给新div赋id值

?

官网原文:

/* 页面基本样式 */
body, td, input, textarea {
    font-family:Arial;
    font-size:12px;
}

If the model state is invalid the JsonResult contains the result string ‘fail’ as well as the rendered HTML from the AddComment partial, but using the comment object which has an invalid state, which will therefore render the required error message due to the required validation attribute on the model.

through on self

through can be used for a model bound to itself using a bridge model. In our case it's a user mentoring other users:

through self ER

图片 9

That's how we can define relations for this case:

class User extends CActiveRecord
{
    ...
    public function relations()
    {
        return array(
            'mentorships'=>array(
                self::HAS_MANY,'Mentorship','teacher_id','joinType'=>'INNER JOIN'
            ),
            'students'=>array(
                self::HAS_MANY,'User',array('student_id'=>'id'),
                    'through'=>'mentorships','joinType'=>'INNER JOIN'
            ),
        );
    }
}

<table class="reply">
<tr>
    <td colspan="2" class="title">回帖<input type="hidden" name="threadid" id="threadid" value="1"></td>
</tr>
<tr>
    <td>姓名:</td>
    <td><input type="text" name="username" id="username"></td>
</tr>
<tr>
    <td>标题:</td>
    <td><input type="text" name="post_title" id="post_title"></td>
</tr>
<tr>
    <td>内容:</td>
    <td><textarea name="post_content" id="post_content"></textarea></td>
</tr>
<tr>
    <td colspan="2"><input type="button" onclick="submitPost()" value="提交"></td>
</tr>
</table>

For editing a post, if you’re used to Linq2Sql or Entity Framework you may do something like this.

HAS_MANY through

HAS_MANY through ER

图片 10

An example of HAS_MANY with through is getting users from a particular group when users are assigned to groups via roles.

A bit more complex example is getting all comments for all users of a particular group. In this case we have to use several relations with through in a single model:

class Group extends CActiveRecord
{
    ...
    public function relations()
    {
        return array(
            'roles'=>array(self::HAS_MANY,'Role','group_id'),
            'users'=>array(
                self::HAS_MANY,'User',array('user_id'=>'id'),'through'=>'roles'
            ),
            'comments'=>array(
                self::HAS_MANY,'Comment',array('id'=>'user_id'),'through'=>'users'
            ),
        );
    }
}

先看xin.sql数据库,我们可直接复制保存成xxx.sql哦。

Anyway, on with the tutorial… I’d suggest reading the documentation on the MongoDB website and also the books by Kristina Chodorow. Also if you want a visual representation of your data I’d suggest having a look at MongoVue.

6. Dynamic Relational Query Options 

We can use dynamic relational query options in both with() and the with option. The dynamic options will overwrite existing options as specified in the relations() method. For example, with the above User model, if we want to use eager loading approach to bring back posts belonging to an author in ascending order (theorder option in the relation specification is descending order), we can do the following:

User::model()->with(array(
    'posts'=>array('order'=>'posts.create_time ASC'),
    'profile',
))->findAll();

Dynamic query options can also be used when using the lazy loading approach to perform relational query. To do so, we should call a method whose name is the same as the relation name and pass the dynamic query options as the method parameter. For example, the following code returns a user's posts whose status is 1:

$user=User::model()->findByPk(1);
$posts=$user->posts(array('condition'=>'status=1'));
  • "]");  //创建标题div
        var postContentDiv = createDiv("post_content", "<pre>" + content + "</pre>");    //创建内容div
        postDiv.appendChild(postTitleDiv);                          //在外层div追加标题
        postDiv.appendChild(postContentDiv);                        //在外层div追加内容

MongoDB is also the only NOSQL database I’m aware of that has commerical support from its creators, 10gen.

8. Statistical Query 

Besides the relational query described above, Yii also supports the so-called statistical query (or aggregational query). It refers to retrieving the aggregational information about the related objects, such as the number of comments for each post, the average rating for each product, etc. Statistical query can only be performed for objects related in HAS_MANY (e.g. a post has many comments) or MANY_MANY (e.g. a post belongs to many categories and a category has many posts).

Performing statistical query is very similar to performing relation query as we described before. We first need to declare the statistical query in the relations() method of CActiveRecord like we do with relational query.

class Post extends CActiveRecord
{
    public function relations()
    {
        return array(
            'commentCount'=>array(self::STAT, 'Comment', 'post_id'),
            'categoryCount'=>array(
                self::STAT, 'Category', 'post_category(post_id, category_id)'
            ),
        );
    }
}

In the above, we declare two statistical queries: commentCount calculates the number of comments belonging to a post, and categoryCount calculates the number of categories that a post belongs to. Note that the relationship between Post and Comment is HAS_MANY, while the relationship between Post and Category isMANY_MANY (with the joining table post_category). As we can see, the declaration is very similar to those relations we described in earlier subsections. The only difference is that the relation type is STAT here.

With the above declaration, we can retrieve the number of comments for a post using the expression $post->commentCount. When we access this property for the first time, a SQL statement will be executed implicitly to retrieve the corresponding result. As we already know, this is the so-called lazy loading approach. We can also use the eager loading approach if we need to determine the comment count for multiple posts:

$posts=Post::model()->with('commentCount', 'categoryCount')->findAll();

The above statement will execute three SQLs to bring back all posts together with their comment counts and category counts. Using the lazy loading approach, we would end up with 2*N+1 SQL queries if there are Nposts.

By default, a statistical query will calculate the COUNT expression (and thus the comment count and category count in the above example). We can customize it by specifying additional options when we declare it inrelations(). The available options are summarized as below.

  • select: the statistical expression. Defaults to COUNT(*), meaning the count of child objects.

  • defaultValue: the value to be assigned to those records that do not receive a statistical query result. For example, if a post does not have any comments, its commentCount would receive this value. The default value for this option is 0.

  • condition: the WHERE clause. It defaults to empty.

  • params: the parameters to be bound to the generated SQL statement. This should be given as an array of name-value pairs.

  • order: the ORDER BY clause. It defaults to empty.

  • group: the GROUP BY clause. It defaults to empty.

  • having: the HAVING clause. It defaults to empty.

/* 回帖表格表头样式 */
table.reply td.title {
    background:#003366;
    color:#FFFFFF;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
public void Create(Post post)
{
    var con = new MongoConnectionStringBuilder(
        ConfigurationManager.ConnectionStrings["MongoDB"].ConnectionString);
 
    var server = MongoServer.Create(con);
    var db = server.GetDatabase(con.DatabaseName);
    var collection = db.GetCollection<Post>("post");
 
    post.Comments = new List<Comment>();
 
    collection.Save(post);
}

3. 关系型查询选项 

我们提到在关系声明时可以指定附加的选项。这些 名-值 对形式的选项用于自定义关系型查询。概括如下:

  • select: 关联的 AR 类中要选择(select)的列的列表。 默认为 '*',即选择所有列。此选项中的列名应该是已经消除歧义的。

  • condition: 即 WHERE 条件。默认为空。此选项中的列名应该是已经消除歧义的。

  • params: 要绑定到所生成的 SQL 语句的参数。应该以 名-值 对数组的形式赋值。此选项从 1.0.3 版起有效。

  • on: 即 ON 语句。此处指定的条件将会通过 AND 操作符附加到 join 条件中。此选项中的列名应该是已经消除歧义的。 此选项不会应用到 MANY_MANY 关系中。此选项从 1.0.2 版起有效。

  • order: 即 ORDER BY 语句。默认为空。 此选项中的列名应该是已经消除歧义的。

  • with: a list of child related objects that should be loaded together with this object. Be aware that using this option inappropriately may form an infinite relation loop.

  • joinType: type of join for this relationship. It defaults to LEFT OUTER JOIN.

  • alias: the alias for the table associated with this relationship. It defaults to null, meaning the table alias is the same as the relation name.

  • together: whether the table associated with this relationship should be forced to join together with the primary table and other tables. This option is only meaningful for HAS_MANY and MANY_MANY relations. If this option is set false, the table associated with the HAS_MANY or MANY_MANY relation will be joined with the primary table in a separate SQL query, which may improve the overall query performance since less duplicated data is returned. If this option is set true, the associated table will always be joined with the primary table in a single SQL query, even if the primary table is paginated. If this option is not set, the associated table will be joined with the primary table in a single SQL query only when the primary table is not paginated. For more details, see the section "Relational Query Performance".

  • join: the extra JOIN clause. It defaults to empty. This option has been available since version 1.1.3.

  • group: the GROUP BY clause. It defaults to empty. Column names referenced in this option should be disambiguated.

  • having: the HAVING clause. It defaults to empty. Column names referenced in this option should be disambiguated.

  • index: the name of the column whose values should be used as keys of the array that stores related objects. Without setting this option, an related object array would use zero-based integer index. This option can only be set for HAS_MANY and MANY_MANY relations.

  • scopes: scopes to apply. In case of a single scope can be used like 'scopes'=>'scopeName', in case of multiple scopes can be used like 'scopes'=>array('scopeName1','scopeName2'). This option has been available since version 1.1.9.

In addition, the following options are available for certain relationships during lazy loading:

  • limit: limit of the rows to be selected. This option does NOT apply to BELONGS_TO relation.

  • offset: offset of the rows to be selected. This option does NOT apply to BELONGS_TO relation.

  • through: name of the model's relation that will be used as a bridge when getting related data. This option has been available since version 1.1.7 where it can be used for HAS_ONE and HAS_MANY. Since 1.1.14 it can be used for BELONGS_TO as well.

Below we modify the posts relationship declaration in the User by including some of the above options:

class User extends CActiveRecord
{
    public function relations()
    {
        return array(
            'posts'=>array(self::HAS_MANY, 'Post', 'author_id',
                            'order'=>'posts.create_time DESC',
                            'with'=>'categories'),
            'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
        );
    }
}

Now if we access $author->posts, we would obtain the author's posts sorted according to their creation time in descending order. Each post instance also has its categories loaded.

bbs.js文件,里面包括了大量ajax文件啊

1
2
3
4
5
var con = new MongoConnectionStringBuilder(ConfigurationManager.ConnectionStrings["MongoDB"].ConnectionString);
 
var server = MongoServer.Create(con);
var db = server.GetDatabase(con.DatabaseName);
var collection = db.GetCollection<Post>("post");

1. 声明关系 

在我们使用 AR 执行关联查询之前,我们需要让 AR 知道一个 AR 类是怎样关联到另一个的。

两个 AR 类之间的关系直接通过 AR 类所代表的数据表之间的关系相关联。 从数据库的角度来说,表 A 和 B 之间有三种关系:一对多(one-to-many,例如 tbl_user 和 tbl_post),一对一( one-to-one 例如 tbl_user 和tbl_profile)和 多对多(many-to-many 例如 tbl_category 和 tbl_post)。 在 AR 中,有四种关系:

  • BELONGS_TO(属于): 如果表 A 和 B 之间的关系是一对多,则 表 B 属于 表 A (例如 Post 属于 User);

  • HAS_MANY(有多个): 如果表 A 和 B 之间的关系是一对多,则 A 有多个 B (例如 User 有多个 Post);

  • HAS_ONE(有一个): 这是 HAS_MANY 的一个特例,A 最多有一个 B (例如 User 最多有一个 Profile);

  • MANY_MANY: 这个对应于数据库中的 多对多 关系。 由于多数 DBMS 不直接支持 多对多 关系,因此需要有一个关联表将 多对多 关系分割为 一对多 关系。 在我们的示例数据结构中,tbl_post_category 就是用于此目的的。在 AR 术语中,我们可以解释 MANY_MANY 为 BELONGS_TO 和 HAS_MANY 的组合。 例如,Post 属于多个(belongs to many) Category ,Category 有多个(has many) Post.

AR 中定义关系需要覆盖 CActiveRecord 中的 relations() 方法。此方法返回一个关系配置数组。每个数组元素通过如下格式表示一个单一的关系。

'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...additional options)

其中 VarName 是关系的名字;RelationType 指定关系类型,可以是一下四个常量之一: self::BELONGS_TO,self::HAS_ONEself::HAS_MANY and self::MANY_MANYClassName 是此 AR 类所关联的 AR 类的名字;ForeignKey 指定关系中使用的外键(一个或多个)。额外的选项可以在每个关系的最后指定(稍后详述)。

以下代码演示了怎样定义 User 和 Post 类的关系:

class Post extends CActiveRecord
{
    ......

    public function relations()
    {
        return array(
            'author'=>array(self::BELONGS_TO, 'User', 'author_id'),
            'categories'=>array(self::MANY_MANY, 'Category',
                'tbl_post_category(post_id, category_id)'),
        );
    }
}

class User extends CActiveRecord
{
    ......

    public function relations()
    {
        return array(
            'posts'=>array(self::HAS_MANY, 'Post', 'author_id'),
            'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
        );
    }
}

信息: 外键可能是复合的,包含两个或更多个列。 这种情况下,我们应该将这些外键名字链接,中间用空格或逗号分割。对于 MANY_MANY 关系类型, 关联表的名字必须也必须在外键中指定。例如, Post中的 categories 关系由外键 tbl_post_category(post_id, category_id) 指定。

AR 类中的关系定义为每个关系向类中隐式添加了一个属性。在一个关联查询执行后,相应的属性将将被以关联的 AR 实例填充。 例如,如果 $author 代表一个 User AR 实例, 我们可以使用 $author->posts 访问其关联的Post 实例。

bbspost.php文件

Next let’s do the detail page that displays the full post. On this page I’m going to allow adding comments as well as displaying the current comments and loading more via ajax. Here is the service method that gets a single post via the Url.

10. Relational Query with through 

When using through, relation definition should look like the following:

'comments'=>array(self::HAS_MANY,'Comment',array('key1'=>'key2'),'through'=>'posts'),

 

In the above array('key1'=>'key2'):

  • key1 is a key defined in relation specified in through (posts is this case).
  • key2 is a key defined in a model relation points to (Comment in this case).

through can be used with HAS_ONEBELONGS_TO and HAS_MANY relations.

/* 文字区域样式 */
textarea {
    width:200px;
    height:50px;
}

I can then change my code to look like this.

图片 11

<body>
<h1>无刷新显示回帖</h1>
<div id="thread">
<?
 $conn = @mysql_connect("localhost","root","123") or die ("MySql连接错误");
 mysql_select_db("xin",$conn);
 mysql_query("set names 'utf8'");
 $sql = "select * from bbs_post where threadid = 1 order by id asc";
 $query = mysql_query($sql);
 while($row = mysql_fetch_array($query)){
?>
   <div class="post" id="post<?=$row[id]?>">
                <div class="post_title"><?=$row[title]?> [<?=$row[username]?>]</div>
                <div class="post_content"><pre><?=$row[content]?></pre></div>
         </div>
<?
 }
?>
</div>

?

 代码如下

Here is the jQuery that hijaxes the form and updates the DOM.

$conn = @ mysql_connect("localhost", "root", "123") or die("MySql连接错误");
mysql_select_db("xin", $conn);
mysql_query("set names 'utf8'");

?

//检查表单是否内容已填写完毕
function checkForm() {
    if (username == "") {
        alert("请填写姓名");
        return false;
    } else if (title == "") {
        alert("请填写标题");
        return false;
    } else if (content == "") {
        alert("请填写内容");
        return false;
    }
    return true;
}

Here is the partial view that’s used for rendering a comment.

//根据className和text创建新的div
function createDiv(className, text) {
    var newDiv = document.createElement("div");
    newDiv.className = className;
    newDiv.innerHTML = text;
    return newDiv;
}

My post action for creating looks like this.

    var postTitleDiv = createDiv("post_title", title + " [" + username

And my view like this.

/* 帖子title的样式 */
div.post_title {
    border-bottom:1px dotted #0066CC;
    font-weight:bold;
}

You can see that it has a remove link to delete a comment. Lets look at the service method used to do this.

$sql="insert into bbs_post (title,content,username,threadid) " .
    "values ('$title','$content','$username','$threadId')";
   echo $sql;
   mysql_query($sql);
  //传回最后一次使用 INSERT 指令的 ID
 $responseId=mysql_insert_id();
 echo $responseId;
?>

1
2
3
4
5
6
7
8
[HttpGet]
public ActionResult Detail(string id)
{
    var post = _postService.GetPost(id);
    ViewBag.PostId = post.PostId;
 
    return View(post);
}

/* 回帖表格单元格样式 */
table.reply td {
    border:1px solid black;
    padding:3px;
}

?

//获取查询选项的回调函数
function submitPostCallBack() {
    if (xmlHttp.readyState == 4) {
     alert(xmlHttp.responseText);
        createNewPost(xmlHttp.responseText);
    }
}

Another cool feature of MongoDB is upserts. This is where if the document exists it is updated, otherwise a new document is inserted. Upserts can be done using the FindAndModify method and using the overload with the upsert argument and setting it to true.

//先创建一个空的bbs.js文件,并修改其属性为utf-8,才能保存中文。
var xmlHttp;                        //用于保存XMLHttpRequest对象的全局变量
var username;                       //用于保存姓名
var title;                          //用于保存标题
var content;                        //用于保存内容
var threadid;                       //用于保存主题编号

The view renders each comment, then if the number of TotalComments is greater than the LoadedComments, ie. there are more comments to load, it renders a ‘Load more’ link which will load more comments using ajax. Here I’m using a data attribute in the anchor tag which contains the number of loaded comments. This is so I can easily get this number from my jQuery method to load the  next page.

    document.getElementById("thread").appendChild(postDiv);     //将外层div追加到主题div中
}

I’ve added a link to my page to create new posts and then used DisplayForModel to show my display template that looks like this.

//用于创建XMLHttpRequest对象
function createXmlHttp() {
    //根据window.XMLHttpRequest对象是否存在使用不同的创建方式
    if (window.XMLHttpRequest) {
       xmlHttp = new XMLHttpRequest();                  //FireFox、Opera等浏览器支持的创建方式
    } else {
       xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");//IE浏览器支持的创建方式
    }
}

?

/* 预定义格式样式 */
pre {
    margin:0;
}

1
2
3
4
5
public ActionResult RemoveComment(ObjectId postId, ObjectId commentId)
{
_commentService.RemoveComment(postId, commentId);
return new EmptyResult();
}

郑重声明:本文版权归新匍京a奥门-最全网站手机版app官方下载所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。