2010年5月15日

WCF-REST和POCO無窮迴圈的問題

這陣子在寫REST配合上EF4和POCO
Lazy Loading的不支援這已經不用講了....
同樣的Proxy也一樣必須關掉,
但還是碰上一個問題,
明明在除錯模式看的時候,物件裡面的值也都有,是正常的,
但實際上,打開的網頁就是一片空白。
後來終於找到相關網站如下

http://nikhilthaker86.wordpress.com/tag/wcf-rest/

翻譯後大約的意思是( 翻錯了不要打我- -)
因為在呼叫的時候,會變成Customer 取得 Orders,
然後Orders裡面又取得Customer 然後,Customer又取得Orders
變成無窮迴圈取得,使得序列化沒辦法產生出來。

目前找到的方法是使用
[IgnoreDataMember]
這個參數是將此屬性不要序列化,
但同樣也有些問題,如果將Customer的Orders屬性關掉的話,
就變成,可以從Orders取得Customer屬性,但卻無法從Customer取得Orders

P.S 解決著個問題,大概一口氣看了我這輩子最多的英文文章吧= =

[IgnoreDataMember]
public virtual ICollection<Orders> Orders
{
  get
  {
    if (_orders == null)
    {
      var newCollection = new FixupCollection<Orders>();
      newCollection.CollectionChanged += FixupOrders;
      _orders = newCollection;
    }
  return _orders;
  }
  set
  {
    if (!ReferenceEquals(_orders, value))
    {
      var previousValue = _orders as FixupCollection<Orders>;
      if (previousValue != null)
      {
        previousValue.CollectionChanged -= FixupOrders;
      }
      _orders = value;
      var newValue = value as FixupCollection<Orders>;
      if (newValue != null)
      {
        newValue.CollectionChanged += FixupOrders;
      }
    }
  }
}

private ICollection<Orders> _orders;

2010年5月7日

SQL Manager express 防止儲存變更

前幾天在公司碰到一個問題
不允許儲存變更。您所做的變更需要卸除並重新建立下列的資料表。 您有任何所做變更至資料表,且無法重新建立或啟用 [防止儲存變更] 選項時,需要重新建立資料表。


其實很簡單,因為SQL Manager express 預設是不給直接變更的。

工具(T) → 選項(O) → Designers
有邊下面有一個 防止儲存需要資料表重建的變更(S) 。
沒錯,把那個核取方塊取消掉吧,就可以變更了

DataTable新增資料之效率問題

最近讀到一篇不錯的文章,
內容是在說使用DataTable新增資料,怎樣才會快
原文
此外,原作者還有很多不錯的文章,大家可以去看看。

我引用了這篇原文,順便加上些自己的看法與註解。

DataTable 新增資料,這麼簡單的問題有誰不會?但是您用對方法了嗎?如果是新增一筆資料給使用者輸入,用什麼方法沒有太大的差別,但如果是用程式碼大量新增資料,不同的方法時間可以差上數倍,欄位越多越明顯,廢話不多說,直接看不同的寫法測試數據

測試 20 個字串欄位及 20 個整數欄位, 無 Constraints, 新增 10000 筆資料,
每種方法測試10次, 去除最大及最小值後分列列出其餘8次中 (最小值, 平均值, 最大值), 單位 Milliseconds
( 有興趣者可測試有 Constraints 時方法一與方法二的差異 )

方法一 ( 405.6, 416.0, 426.4 )

DataRow row;
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  row = table.NewRow();
  for (int i = 1; i <= ColCount; i++)
  {
    row["ColString" + i.ToString()] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    row["ColInt" + i.ToString()] = rowIndex * 1000 + i;
  }
table.Rows.Add(row);
}

SanC : 這是我們最常用的方法,在撰寫時,算是最直覺的寫法。

方法二 ( 390.0, 395.9, 405.6 )

DataRow row;
table.BeginLoadData();
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  row = table.NewRow();
  for (int i = 1; i <= ColCount; i++)
  {
    row["ColString" + i.ToString()] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    row["ColInt" + i.ToString()] = rowIndex * 1000 + i;
  }
table.Rows.Add(row);
}
table.EndLoadData();

SanC:
這個方法修正了方法一的地方,
最顯著的是將使用table.BeginLoadData()和table.EndloadData()放在最外圈,
我的猜測,再沒寫這兩個Function時,當執行10000次時,也同時呼叫了10000次的這兩個function
所以,速度也慢了。

方法三 ( 234.0, 245.1, 254.8 )

int[] strColIndex = new int[ColCount];
int[] intColIndex = new int[ColCount];
for (int i = 1; i <= ColCount; i++)
{
  strColIndex[i - 1] = table.Columns["ColString" + i.ToString()].Ordinal;
  intColIndex[i - 1] = table.Columns["ColInt" + i.ToString()].Ordinal;
}

DataRow row;
table.BeginLoadData();
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  row = table.NewRow();
  for (int i = 1; i <= ColCount; i++)
  {
    row[strColIndex[i - 1]] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    row[intColIndex[i - 1]] = rowIndex * 1000 + i;
  }
table.Rows.Add(row);
}
table.EndLoadData();

SanC:
這裡使用陣列strColIndex和intColIndex來存欄位名稱的編號
( 例如: 欄位名稱ColSting1的編號為1 ColString2的編號為2 )
此陣列就是來存取此值,
然後在新增資料的時候,使用的不是用字串當索引
( 字串當索引 row["ColString1"] )
而是使用數字( 編號 )當索引,在不經過查詢(轉換)的過程,
使得速度更快了。

方法四 ( 119.6, 127.4, 135.2 ) - 較佳寫法, 使用 object[] 新增資料

int[] strColIndex = new int[ColCount];
int[] intColIndex = new int[ColCount];
for (int i = 1; i <= ColCount; i++)
{
  strColIndex[i-1] = table.Columns["ColString" + i.ToString()].Ordinal;
  intColIndex[i-1] = table.Columns["ColInt" + i.ToString()].Ordinal;
}

object[] itemArray;
table.BeginLoadData();
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  itemArray = new object[table.Columns.Count];
  for (int i = 1; i <= 10; i++)
  {
    itemArray[strColIndex[i-1]] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    itemArray[intColIndex[i-1]] = rowIndex * 1000 + i;
  }
table.Rows.Add(itemArray);
}
table.EndLoadData();

SanC:
又更加的改進,這裡使用object來做處理,而非使用DataRow來新增,
先建立一個名為 itemArray的object陣列
然後再將每個資料塞到陣列裡的每個物件裡,
然後再用table.Rows.Add(itemArray)來新增所有資料
這是最快的處理方法,至於為何,只能猜測因為object型別最單純!?
或是中間不需要經過轉換的過程。

2010年5月3日

RSS 2.0 樣板

這是最近寫的一個RSS樣本..
<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
<channel>
<title>San.C的美味程式廚房</title>
<link>http://blog.sanc.idv.tw</link>
<description>San.C的美味程式廚房RSS</description>
<!-- 圖片註解
<image>
<url>http://xxx.com/xx.gif</url>
<title>San.C的美味程式廚房</title>
<link>http://blog.sanc.idv.tw</link>
</image>
-->
<language>zh-tw</language>
<!-- 版權宣告
<copyright>Copyright 2010 Blog.sanc.idv.tw</copyright>
-->
<generator>San.C http://blog.sanc.idv.tw/</generator>
<!-- iTunes定義 -->
<itunes:summary>SanC 美味程式廚房 By iTunes </itunes:summary>
<itunes:author>SanC 美味程式廚房</itunes:author>
<itunes:subtitle>SanC 美味程式廚房 更多好料,通通在此!</itunes:subtitle>
<itunes:keywords>SanC 美味程式廚房 程式 亂七八糟</itunes:keywords>
<itunes:owner>
<itunes:name>SanC</itunes:name>

這是最近弄的一個RSS 2.0的樣板
<pre>
<itunes:email>xxx@xxxx</itunes:email>
</itunes:owner>
<itunes:image href="http://xxx.com/xxx.jpg" />
<itunes:link rel="image" type="video/jpeg"
href="http://xxx.com/xxx.jpg">SanC 美味程式廚房</itunes:link>

<item>
<title><![CDATA[標題]]></title>
<link>http://xx.com/位置</link>
<!-- 為一位置,通常與Link同-->
<guid isPermaLink="true">http://xx.com/位置</guid>
<!--評論網址
<comments>http://</comments>
-->
<channels><channel>類別</channel></channels>
<description><![CDATA[ 可以插入HTML但,Outlook可能會讀不到部分東西]]>
</description>
<!-- 分類標籤
<category>標籤1</category>
<category>標籤2</category>
-->
<dc:creator><![CDATA[San.C]]></dc:creator>
<!-- 時間,以下為固定格式 -->
<pubDate>Thu, 30 Apr 2010 10:46:00 EST</pubDate>
</item>

<!-- iTumes 專區 -->
<item>
<title>標題</title>
<pubDate>2010/01/29</pubDate>
<itunes:author>San.C</itunes:author>
<description>iTunes測試</description>
<itunes:subtitle>iTunes測試</itunes:subtitle>

<enclosure url="http://www.XXXX.com.tw/XXXX.MP3" length="2483024"
type="audio/mpeg"/>
<guid  ispermalink="true">http://www.XXXX.com.tw/XXXX.MP3</guid>
</item>

</channel>
</rss>

安裝 Team Foundation Server 錯誤 TF255356 解決方案

這是之前安裝Team Foundation Server時發生的一個錯誤
如下:
TF255356 Error occured during servicing step Add Running User to the TFSADMINROLE

TF255356: The following error occurred when configuring the Team Foundation databases: Error occurred while executing servicing step Add Running User to the TFSADMINROLE for component Install during Install: ModifyExecRole.sql Line 2 Error: The server principal 'NIMBLE\Administrator' already exists.
ModifyExecRole
account=NIMBLE\Administrator
operation=1
Adding ...
checking if login exists
NIMBLE\Administrator is not a login. creating login.. For more information, see the configuration log.

其實問題的發生很簡單,因為在裝完SQL Server後,
手賤的又去改了電腦名稱,所以造成SQL Server的帳號還是沿用舊的電腦名稱,
自然的,再裝Team Foundation Server時,就因為帳號不對,進不去了。

解決方法,進入SQL Server 然後把帳號改成現在電腦名稱的帳號,就可以了=w=

jQuery呼叫Web Service

對jQuery來說,這是最基本不過的事情了....
PO在這裡的用處是可以直接可以讓我Copy程式碼XD
省掉去官網尋找的時間= =+
以下是用Post呼叫....

//jQuery 呼叫Web service by POST
//1.使用 ajax物件
$.ajax({
  type: 'post',
  url: "../webService/helow.asmx/helow",
  //要傳過去的值
  data:'name=' + 變數1 + '&Text=' + 變數2,
  //成功接收的function
  success: function(oXml) {
    //先將xml轉成jQuery物件
    var x = $(oXml);
    //用find和text來做擷取
    alert(x.find("string").text());
},
error: function() { alert('ajax failed'); }
});

//2.用post物件呼叫
$.post("../webService/helow.asmx/sendHTMLMail",
{ name:變數1, text:變數2 },
function(data)
{
  var x = $(data);
  alert(x.find("string").text());
  },"xml"
);

ASP利用Post呼叫ASP.NET Web Service

雖然 ASP已經十年了,但還是有很多地方會用到ASP
而要讓新舊並存,還是有一些方法,
例如透過Service的方式之類的。

而下面就是利用ASP傳一個Post去呼叫一個Service
( 這裡的Service是.NET建構出來的Web Service )
Dim xmlhttp
Dim DataToSend
DataToSend="name=Sanc&text=世界您好"
Dim postUrl
postUrl = "http://localhost/webservice/hello.asmx/helloWorld"
Set xmlhttp = server.Createobject("MSXML2.ServerXMLHTTP")
xmlhttp.Open "POST",postUrl,false
xmlhttp.setRequestHeader "Content-Type","application/x-www-form-urlencoded"
xmlhttp.send DataToSend


這樣就可以做最簡單的呼叫了~~

Flex 4 - 驗證 - NumberValidator

Flex - 美味食譜 -  驗證工具NumberValidator

這是Flex裡很基本的一個驗證工具,
可以拿來驗證InputBox裡面是否為數字

快速範例:

<mx:NumberValidator source="{目標物件}" property="text"
minValue="12"   //數字最小
maxValue="120"  //數字最大
domain="int"    //型態
requiredFieldError="此為必填欄位"    //未填時提示
lowerThanMinError="你輸入的數字太小" //數字太小提示
exceedsMaxError="你輸入的數字超過了" //數字超過提式
invalidCharError="請輸入數字"        //輸入非數字
integerError="數值錯誤"              //int 錯誤
trigger="{Button}"                   //觸發物件
triggerEvent="click"                 //觸發事件
/>

有時,會需要一次檢驗大量的表單,可以用下面這個範例
大量一次檢查範例

<fx:Declarations>
<mx:NumberValidator id="nv" source="{目標}" property="text"
requiredFieldError="請填入數值,如沒有請填零"
invalidCharError="填寫有誤,請輸入數值"
integerError="請輸入數值"
minValue="0" domain="int"
trigger="{nextButton}" triggerEvent="click"
/>
<mx:NumberValidator id="nv2" source="{目標}" property="text"
requiredFieldError="請填入數值,如沒有請填零"
invalidCharError="填寫有誤,請輸入數值"
integerError="請輸入數值"
minValue="0" domain="int"
trigger="{nextButton}" triggerEvent="click"
/>

<mx:NumberValidator id="nv3" source="{目標}" property="text"
requiredFieldError="請填入數值,如沒有請填零"
invalidCharError="填寫有誤,請輸入數值"
integerError="請輸入數值"
minValue="0" domain="int"
trigger="{nextButton}" triggerEvent="click"
/>
</fx:Declarations>

private function go():void{
myValidators = [nv,nv2,nv3];
//驗證大量表單
var error:Array=Validator.validateAll(myValidators);

if(error.length != 0 )
{
  Alert.show("您輸入的金額可能有誤,煩請重新確認");
  }else{
    Alert.show("成功")
  }

}