[置顶]经典文章翻译: 弥合对象/关系之间的鸿沟(五)
[置顶]经典文章翻译: 弥合对象/关系之间的鸿沟(四)
[置顶]经典文章翻译: 弥合对象/关系之间的鸿沟(三)
[置顶]经典文章翻译: 弥合对象/关系之间的鸿沟(二)
[置顶]经典文章翻译: 弥合对象/关系之间的鸿沟(一)
javascript 调用 IndexedDb示例
一个简单的Todolist
html
todo.html
<!DOCTYPE html> <html> <head> <title>candyDatabase sample</title> <script type="text/javascript" src="todo.js"></script> </head> <body> <ul id="todolist"></ul> <input type="text" id="tbx_todo" name="todo" placeholder="pls enter a todo-item here" /> <input type="submit" value="添加待办项" onclick="addTodo(); return false;"/> </body> </html>
javascript代码
todo.js
/** * @author Scott * */ var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB; if ('webkitIndexedDB' in window) { window.IDBTransaction = window.webkitIDBTransaction; window.IDBKeyRange = window.webkitIDBKeyRange; } candyDb = {}; candyDb.db = null; candyDb.onerror = function(e) { console.log(e); }; candyDb.open = function() { var request = indexedDB.open("candyDb", '202'); request.onsuccess = function(e) { candyDb.db = this.result; candyDb.getAllTodoItems(); }; request.onupgradeneeded = function(evt) { candyDb.db = this.result; if (candyDb.db.objectStoreNames.contains("todo")) { candyDb.db.deleteObjectStore("todo"); } var store = candyDb.db.createObjectStore("todo", { keyPath : "id" }); console.log("upgraded...") }; request.onerror = candyDb.onerror; } candyDb.addTodo = function(todoText) { var db = candyDb.db; var trans = db.transaction(["todo"], "readwrite"); var store = trans.objectStore("todo"); var data = { "text" : todoText, "priority" : 0, "id" : new Date().getTime() }; var request = store.put(data); request.onsuccess = function(e) { candyDb.getAllTodoItems(); }; request.onerror = function(e) { console.log("Error Adding: ", e); }; }; candyDb.deleteTodo = function(id) { var db = candyDb.db; var trans = db.transaction(["todo"], "readwrite"); var store = trans.objectStore("todo"); var request = store.delete(id); request.onsuccess = function(e) { candyDb.getAllTodoItems(); }; request.onerror = function(e) { console.log("Error Adding: ", e); }; }; candyDb.getAllTodoItems = function() { var todos = document.getElementById("todoItems"); todos.innerHTML = ""; var db = candyDb.db; var trans = db.transaction(["todo"], "readwrite"); var store = trans.objectStore("todo"); var keyRange = IDBKeyRange.lowerBound(0); var cursorRequest = store.openCursor(keyRange); cursorRequest.onsuccess = function(e) { var result = e.target.result; if (!!result == false) return; renderTodo(result.value); result.continue(); }; cursorRequest.onerror = candyDb.onerror; }; function renderTodo(row) { var todos = document.getElementById("todolist"); var li = document.createElement("li"); var a_del = document.createElement("a"); var txt = document.createTextNode(row.text); a_del.addEventListener("click", function() { candyDb.deleteTodo(row.id); }, false); a_del.textContent = " [delete]"; li.appendChild(txt); li.appendChild(a_del); todos.appendChild(li) } function addTodo() { var todo = document.getElementById("tbx_todo"); candyDb.addTodo(todo.value); todo.value = ""; } function init() { candyDb.open(); } window.addEventListener("DOMContentLoaded", init, false);
如何查看MS-Acccess中主键的名字
原文链接: 如何查看acccess中主键的名字
创建access主键的时候有两种方式,一种是在access中手动创建的,另一种是在用代码创建的(不管是在access中执行的还是在外部程序)。
方式不同主键名称也不同,第一种创建方式的主键名字都是primarykey,注意中间没有空格;第二种主键的名字需要借助VBA代码才能查出来:
Public Sub fnGetPrimaryKeyName() Dim v_DB As New ADOX.Catalog Dim v_Table As ADOX.Table Dim v_Key As ADOX.Key Dim objTable As New ADOX.Table Dim strKey As String Dim strKeyName As String v_DB.ActiveConnection = CurrentProject.Connection objTable.ParentCatalog = v_DB Set objTable = v_DB.Tables( "你的表名 ") For Each v_Key In objTable.Keys Select Case v_Key.Type Case adKeyPrimary strKey = "Primary KEY " strKeyName = v_Key.Name End Select Next Debug.Print "主键约束名: " & strKeyName End Sub
上述代码需要引用ADOX。
1--> 打开VBA代码窗口
2--> 工具菜单,引用菜单项
3--> 选择“Microsoft ADO Ext. 2.X for DLL and Security”
有一点要注意的是,同一个数据库文件放到不同的地方用代码创建的主键的名字是不同的,这一点要记住。
[翻译] 编写全面的单元测试
编写全面的单元测试
- 版块:开发
- 主题:.net, 单元测试,编程,测试驱动开发,测试


测试FirstName 属性
[TestMethod] public void Person_FirstName_Set() { varperson = new Person("Adam", "Smith"); person.FirstName = "Bob"; Assert.AreEqual("Bob", person.FirstName); }
[TestMethod] public void Person_FirstName_Set_PropertyChanged() { var person = new Person("Adam", "Smith"); var eventAssert = new Granite.Testing.PropertyChangedEventAssert(person); person.FirstName = "Bob"; eventAssert.Expect("FirstName"); }
当我们运行这个测试方法时,我们将受到一条失败信息“期望属性名是‘FirstName’,但是却收到了‘IsChanged’”。显然,设置‘FirstName’属性改变了‘IsChanged’标志属性,所以我们需要考虑到这点,因此我们添加一些代码混合到这段代码中:
[TestMethod]
public void Person_FirstName_Set_PropertyChanged()
{
var person = new Person("Adam", "Smith");
var eventAssert = new Granite.Testing.PropertyChangedEventAssert(person);
person.FirstName = "Bob";
eventAssert.SkipEvent(); //this was IsChanged//这里是IsChanged
eventAssert.Expect("FirstName");
}
[TestMethod]
public void Person_FullName_Changed_By_Setting_FirstName()
{
var person = new Person("Adam", "Smith");
person.FirstName = "Bob";
Assert.AreEqual("Bob Smith", person.FullName);
}
[TestMethod]
public void Person_IsChanged_Changed_By_Setting_FirstName()
{
var person = new Person("Adam", "Smith");
person.FirstName = "Bob";
Assert.IsTrue(person.IsChanged);
}
[TestMethod]
public void Person_IsChanged_Property_Change_Notification_By_Setting_FirstName()
{
var person = new Person("Adam", "Smith");
var eventAssert = new PropertyChangedEventAssert(person);
person.FirstName = "Bob";
eventAssert.Expect("IsChanged");
}
[TestMethod]
public void Person_FullName_Property_Change_Notification_By_Setting_FirstName()
{
var person = new Person("Adam", "Smith");
var eventAssert = new PropertyChangedEventAssert(person);
person.FirstName = "Bob";
eventAssert.SkipEvent(); //this was IsChanged
eventAssert.SkipEvent(); //this was FirstName
eventAssert.Expect("FullName");
}
[TestMethod]
public void Person_FirstName_Set_HasErrorsIsFalse()
{
var person = new Person("Adam", "Smith");
person.FirstName = "Bob";
Assert.IsFalse(person.HasErrors);
}
[TestMethod]
public void Person_FirstName_Set_ErrorsChanged_Did_Not_Fire()
{
var person = new Person("Adam", "Smith");
var errorsChangedAssert = new ErrorsChangedEventAssert(person);
person.FirstName = "Bob";
errorsChangedAssert.ExpectNothing();
}
Bring Transactions to the Common Type
经典文章翻译: 弥合对象/关系之间的鸿沟(六)
弥合对象/关系之间的鸿沟(六)
持久性API
O/RM API提供的接口代表运行时环境。API的主要接口封装了到数据库的连接、查询生成器和已经被应用程序引用的领域实例的缓存。在这篇文章中,这个界面被称为会话(Session)。(在不同的API中,这个接口被称为实体管理程序或持久性管理程序,但不管什么名字,都有异曲同工之妙)
在一个多用户环境中,使用多个会话实例让用户相互隔离。每个会话都有其自己的数据库连接和它自己的领域实例缓存。会话高速缓存实现了唯一性保持(uniquing)。如果一个API支持多个线程运行于同一会话中,所有这些线程在会话管理下共享领域对象的改变。
应用程序从一个会话工厂(SessionFactory)获得一个会话,它封装了数据源(连接工厂)和O/RM模型。在会话工厂(SessionFactory)中通常也包括连接池和二级或全局领域对象缓存,它处理与容器的交互。会话工厂(SessionFactory)是引导程序实例,它通常是从系统服务查找,例如JNDI(Java名称和目录接口)或通过XML或属性配置。
数据库事务由事务类(Transaction)表示,应用程序从会话实例获取一个事务实例。一个会话只有一个活动的事务实例(一个会话可以顺序开始并完成多个事务),不同的接口使得关注点得以分离,那么也就是,访问领域实例的应用程序组件和开始和完成事务的应用程序组件是分开的。
数据库查询由查询类(Query)表示,该类的实例由应用程序从会话获得。一个查询实例封装了一个特定的查询,并实现了一个执行的方法,它允许应用程序根据参数从不同的数据库获取不同的数据集。
在一个单元操作正在进行时,应用程序可能对多个领域实例做出很多改变,并在单元操作结束时,由持久性提供程序根据领域实例的更改将变化应用到数据库。
由于数据库模式(schema)中存在外键约束,在领域模型中的改变对应的数据库操作顺序是很重要的。例如,必须先插入一行数据到数据库中,之后另一个新行才能被插入或更改现有的行使其指向新行。同样,若现有行中有一列指向的是一个要被删除的行,必须在该行被删除之前将此列值设置为空。
O/RM的自动确定数据库中的操作顺序的技术,是基于数据库约束实现的,这是O/RM技术相较于其他技术在可用性方面的一个重要特性,因为程序员必须以正确的顺序执行操作。
查询。O/RM带来的主要好处之一是,查询由领域对象模型的方式表示而不是用关系模式的方式。如果领域模型或查询很复杂,这将会很重要。
在设计O/RM的查询语言的挑战之一是使其足够丰富,足以让大多数应用程序查询,但要作出限制,不允许所有对象领域的查询直接映射到SQL。
例如,若要找到Employee类中周薪大于某个参数的所有实例,对应的SQL查询是:
SELECT * FROM EMPLOYEE WHERE WEEKLY_SALARY>?
相应的使用领域对象模型的查询将是:
SELECT FROM FullTimeEmployee
WHERE weeklySalary > :salary
提供程序从领域模型和映射生成SQL。“:”是一个参数标记,它允许应用程序通过名称绑定查询的参数。
在SQL查询中所涉及的所有表都在FROM子句中声明且连接条件都在WHERE子句中显式包含。若要在Employee类的实例中找到一些周薪大于一个参数且在某单位工作的,此SQL会比较复杂:
SELECT E.* FROM EMPLOYEE E, DEPARTMENT D
WHERE E.WEEKLY_SALARY > ? AND D.NAME = ?
AND E.DEPARTMENT = D.ID
相应的使用领域对象模型的查询将是:
SELECT FROM FullTimeEmployee
WHERE weeklySalary > :salary && dept.name = :dept
下一篇 查询中的关系导航