Sinatra::Application class is a Rack objec, i.e. it responds_to? call(env).
Per this documentation, it’s as easy as requiring your application file and run:
#config.ru require './app'run Sinatra::Application
Sinatra::Application class is a Rack objec, i.e. it responds_to? call(env).
Per this documentation, it’s as easy as requiring your application file and run:
#config.ru require './app'run Sinatra::Application
Thou shall not forget to change thy configuration from cascade="save-update" to cascade="merge" when thou uses Session.Merge() to save thy object.
ป้ายกำกับ:nhibernate
If you get this error when calling Spring-based service hosted on IIS, and your service uses NHibernate for data access, and your service returns some objects that must be serialized…check your object graph.
Make sure there is no NHibernate proxy in the object graph (i.e. do not use lazy loading).
To include properties with null values in NHibernate’s Query By Example (QBE), simply call ExcludeNone() on your created example.
For example, a class called ProductSize has 5 properties called Id, Dimension1, Dimension2, Dimension3, and Dimension4. All properties except Dimension1 are nullable. The combination of all dimension fields are unique for each record.
If I pass in an Example object with only Dimension1 set to 1, I want a search criteria like:
where Dimension1 = 1 and Dimension2 is null and Dimension3 is null and Dimension4 is null
NHibernate’s defaul behavior is to exclude all properties with null values when you create an Example object. So, this code would not work:
var productSize = new ProductSize(1, 2, null, null);
var sampleSize = Example.Create(productSize);
var result = session.CreateCriteria<ProductSize>()
.Add(sampleSize)
.UniqueResult();
The generated SQL expression is
where Dimension1 = 1 and Dimension2 = 2
As a result, more than one record may be returned because the query does not include Dimension3 and Dimension4, and you’ll get an IncorrectResultSizeDataAccessException.
Here’s the code that works:
var productSize = new ProductSize(1, 2, null, null);
var sampleSize = Example.Create(productSize).ExcludeNone(); // Include all properties.
var result = session.CreateCriteria<ProductSize>()
.Add(sampleSize)
.UniqueResult();
Using ExcludeNone() tells NHibernate to generate SQL expression based on all properties, including those will null values.
ป้ายกำกับ:nhibernate
Some observations on .NET BindingSource CurrentChanged/PositionChanged/ListChanged event behaviors. Here’s the code for producing the observations.
private DataTable table = new DataTable();
private int i = 1;
private void Form1_Load(object sender, EventArgs e)
{
// Hack: To prevent CurrentChanged from raising more than once, uncomment the line below.
// bindingSource1.DataSource = table;
table.Columns.Add("c1", typeof(string));
for (int j = 0; j < 5; j++)
{
var row = table.NewRow();
row["c1"] = "row " + i;
i++;
table.Rows.Add(row);
}
dataGridView1.DataSource = bindingSource1;
bindingSource1.DataSource = table;
}
When we set DataSource for bindingSource1, CurrentChanged event is raised 3 times, ListChanged event twice, and PositionChanged event once.
When removing the last row, PositionChanged is raised twice (Position set to -1), while CurrentChanged and ListChanged are raised once per each event.
Clearing the table has the same effect has removing the last row.
Removing the first row (when there are more rows below) does not raise PositionChanged event because the Position stays the same. Only the selected value changes.
In summary:
Update (Mar 8, 2010)…
After playing with the code some more, a semi-automatic approach will hopefully keep me more sane while debugging in the long run. The idea is when setting the DataSource, use unsubscribe-resubscribe procedure as mentioned in this post, then get the Current value manually. When adding, removing, clearing, selecting items, use CurrentChanged event as usual.
After spending a few nights trying to test NHibernate eager loading with Spring.NET framework’s AbstractTransactionalDbProviderSpringContextTests, I finally found the trick.
First, clear the session (cache). Second, reload the object. Third, close the session. Finally, verify that the dependent object was loaded correctly and not proxied.
The code below shows a test to check that the product type is loaded with a product.
[Test]
public void GetProductShouldAlsoLoadProductType()
{
var productType = productTypeRepository.Get(0);
Product obj = new Product("A product", productType);
productRepository.Store(obj);
Flush();
// Empty session cache. Clear all loaded objects.
SessionFactory.GetCurrentSession().Clear(); // (1)
var loaded = productRepository.Get(obj.Id); // (2)
Assert.That(loaded, Is.Not.Null);
// Close current session to make sure relevant objects are not proxied.
EndTransaction(); // (3)
Assert.That(NHibernateUtil.IsInitialized(loaded.ProductType), Is.True);
Assert.That(loaded.ProductType.Name, Is.Not.Null.Or.Empty);
}
Note that the order of execution is important. You must clear the cache (1) before reloading the object (2) before closing the session (3) before testing your assertions.
If we do not clear the session cache in step (1), reloading the object (2) then closing the session (3) will still make the test pass. The reason is that even though the session is closed, the proxied object is there in the cache, literally meaning it has been loaded (and initialized). You can access the product type’s properties without any errors.
On the other hand, if you clear the session cache in step (1), loading the object in step (2) will create a proxy to ProductType class instead of a fully initialized object. When you close the session (3), the assertions will fail, and if you access any property of product type (besides its ID), you’ll get an exception saying the session has been closed.
ป้ายกำกับ:nhibernate
สำหรับใครก็ตามที่ต้องทำงานกับระบบที่มีขนาดย่อมขึ้นไปจนถึงใหญ่ ควรหลีกเลี่ยง strong-typed DataSet/DataAdapter ให้ไกลที่สุดเท่าที่จะเป็นไปได้ เพราะ strong-typed DataSet:
สรุปได้ว่า การใช้ strong-typed DataSet เป็นศูนย์กลางของสถาปัตยกรรมระบบเพื่อแทน model และ data layer ทำให้ระบบขาดความยืดหยุ่นในระยะยาว
ถ้าคุณเปลี่ยน model เป็น PONO หลังจาก DataSet คุณมีประมาณ 100 ตาราง ก็แทบไม่ต่างอะไรกับการ rewrite ระบบใหม่ เพราะเปลี่ยน model ก็ต้องเปลี่ยนเรื่อง persistence และต้องเปลี่ยน UI อีกต่างหาก (ไม่ว่าจะเป็นการเรียกใช้ data layer หรือ data binding กับ model)
คำแนะนำ: หลีกเลี่ยง strong-typed DataSet หรือเปลี่ยนไปใช้สถาปัตยกรรมที่อิงกับ PONO ให้เร็วที่สุดก่อนที่ DataSet จะมีขนาดใหญ่เกินไป
ถ้าคุณเจอ TypeInitializationException แบบนี้เวลาเรียกใช้ ContextRegistry.GetContext():
An unhandled exception of type 'System.TypeInitializationException' occurred in WindowsApplication1.exe Additional information: The type initializer for 'Spring.Context.Support.ContextRegistry' threw an exception.
ลองเช็คดูว่ามีการใช้ PropertyPlaceholderConfigurer หรือเปล่า? ถ้ามี ให้เพิ่ม handler สำหรับ section เข้าไปใน app.config ด้วย:
<configSections>
...
<section name="databaseSettings"
type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</configSections>
ป้ายกำกับ:programming, spring
กรณีที่ class มี method ที่ใช้ [Transaction] attribute และ class นั้นไม่มี interface เราต้อง declare method นั้นเป็น virtual เช่น
// Class does not define an interface.
public class CustomerDao
{
// We must declare this transactional method as virtual.
[Transaction]
public virtual void Save(Customer obj)
{
// Save to database.
}
}
ที่จริงเราต้อง define ทุกๆ method และ property ที่ต้องการให้ Spring ใช้เป็น virtual ด้วยซ้ำ เพราะว่า Spring สร้าง class proxy โดยการสร้างอีก class นึงที่ inherit มาจาก CustomerDao และ override ทุก public method/property ที่สามารถ override ได้ (Decorator pattern) เพื่อเพิ่ม advice เข้าไป ส่วน method ที่ไม่ใช่ virtual ไม่สามารถถูก override ได้ เพราะฉะนั้น Spring ก็จะไม่ยุ่งอะไรกับ method พวกนี้
[Transaction] attribute ไม่สามารถทำงานได้กับ method ที่ไม่มี virtual เพราะ Spring ไม่สามารถเพิ่ม transaction advice ครอบ method นั้นๆ ได้
ลองอ่านเพิ่มเติมได้ที่หัวข้อ 13.5.4 Proxying Classes
ป้ายกำกับ:spring
สมมุติว่าเราตั้งค่า object อันนึงใน Spring.NET ชื่อ dataService ซึ่งใช้อีก object นึงชื่อ adoTemplate ทั้งสอง object ถูกตั้งค่าไว้แล้ว
<object id="adoTemplate" type="Spring.Data.Core.AdoTemplate, Spring.Data"> <property name="DbProvider" ref="dbProvider"/> </object> <object id="dataService" type="MyApp.DataService, MyApp"> <property name="AdoTemplate" ref="adoTemplate"/> </object>
DataService เป็น class ใน service layer ธรรมดา ไม่มี interface ไม่มี base class อะไร
[Service]
public class DataService
{
private AdoTemplate adoTemplate;
public AdoTemplate AdoTemplate
{
set { adoTemplate = value; }
}
[Transaction]
public void MyMethod()
{
// This code does not work.
this.adoTemplate.Execute(...);
this.adoTemplate.Execute(...);
}
}
โค้ดด้านบนเป็นโค้ดที่ผิด เพราะสองสาเหตุ
สาเหตุแรกคือ เราไม่ได้ใช้ property AdoTemplate แต่ใช้ field ที่ชื่อ adoTemplate ใน MyMethod ที่ถูกแล้วเราควรใช้ property เพราะฟิลด์นี้อาจไม่ถูก set ค่าเวลา Spring สร้าง proxy ผลที่เกิดก็คือเราจะเจอ NullReferenceException เวลาถึงบรรทัด adoTemplate.Execute(…)
ข้อที่สองคือ เราไม่ได้ประกาศ AdoTemplate เป็น virtual ทำให้ Spring ไม่ได้ set ค่าของ AdoTemplate property เวลาสร้าง context
สรุปแล้ว โค้ดที่ถูกต้องคือ
[Service]
public class DataService
{
private AdoTemplate adoTemplate;
// Don't forget to make this virtual.
public virtual AdoTemplate AdoTemplate
{
set { adoTemplate = value; }
}
[Transaction]
public void MyMethod()
{
// Use property instead of field.
AdoTemplate.Execute(...);
AdoTemplate.Execute(...);
}
}
ป้ายกำกับ:spring