IBATIS.NET Developer Guide
5.1. Installing the Data Mapper for .NET
5.1.1. Setup the Distribution
You can download the latest version of IBATIS.NET from the below official site: http://code.google.com/p/mybatisnet/downloads/list
I’m going to download the IBatis.DataMapper.1.6.2.bin.zip
List of file found under the distribution’s source folder of IBatis.DataMapper.1.6.2.bin.zip
Folder name | Description |
Castle.DynamicProxy | Creating Proxy |
IBatisNet.Common | Assembly of classes shared by DataAccess and DataMapper |
IBatisNet.Common.Logging.Log4Net | Log4Net factory adapter classes |
iBatisNet.DataMapper | The DataMapper framework |
Log4Net | Log4Net factory adapter Base classes |
providers.config | The database provider definition file (XML Configuration file) |
sample.SqlMap.config | The Data Mapper configuration file (XML Configuration file) |
SqlMap.xml | The Data Map definition file (XML Schema File) |
5.1.2. Add Assembly References
Add references to the following files
1. Castle.DynamicProxy.dll
2. iBatisNet.DataMapper.dll
3. iBatisNet.Common.dll
IBatis.NET references
5.1.3. Add XML File Items
Add following xml files to your application
1. providers.config
2. sample.SqlMap.config
3. SqlMap.xml
IBatis.NET XML files
5.2. Provider Configuration File
I want to connect my application to SQL Server 2005, so removed all the other provider section and maintain “sqlServer2005” provider section alone.
Ensure that the enabled attribute is set to true; this is set to false by default in the sample installation files.
Provider Configuration
5.3. Data Mapper Configuration File
Create a copy of sample.SqlMap.config file and rename it with sqlMap.config
5.3.1. The <provider> Element
Name attribute from the “provider.config” file to be defined here based on any one of the database (SQL Server, Oracle, Access, and MySql).
Example:
<provider name=”OleDb1.1″ />
5.3.2. The <datasource> element
The <datasource> element specifies ODBC datasource or connection string for any one database (SQL Server, Oracle, Access, and MySql).
5.3.3. The <sqlMap> Element
<sqlMap> elements for loading a set of Data Map definition. Note that the <sqlMap> elements are nested in a <sqlMaps> element.
Example:
<sqlMaps>
<sqlMap resource=”/Resources/Category.xml”/>
<sqlMap resource=”/Resources/Product.xml”/>
</sqlMaps>
5.4. Create a map
Add another XML file to the root of your project called UsersMap.xml.
5.4.1. The <statements> Element
This block includes following elements
Statement Element |
Attributes |
Child Elements |
Methods |
<statement> | id | All dynamic elements | Insert |
|
parameterClass |
|
Update |
|
resultClass |
|
Delete |
|
listClass |
|
All query methods |
|
parameterMap |
|
|
|
resultMap |
|
|
|
cacheModel |
|
|
|
|
|
|
<insert> | id | All dynamic elements | Insert |
|
parameterClass | <selectKey> | Update |
|
parameterMap | <generate> | Delete |
|
|
|
|
<update> | id | All dynamic elements | Insert |
|
parameterClass | <generate> | Update |
|
parameterMap |
|
Delete |
|
extends |
|
|
|
|
|
|
<delete> | id | All dynamic elements | Insert |
|
parameterClass | <generate> | Update |
|
parameterMap |
|
Delete |
|
extends |
|
|
|
|
|
|
<select> | id | All dynamic elements | All query methods |
|
parameterClass | <generate> |
|
|
resultClass |
|
|
|
listClass |
|
|
|
parameterMap |
|
|
|
resultMap |
|
|
|
cacheModel |
|
|
|
extends |
|
|
|
|
|
|
<procedure> | id | All dynamic elements | Insert |
|
parameterMap |
|
Update |
|
resultClass |
|
Delete |
|
resultMap |
|
All query methods |
|
cacheModel |
|
|
|
|
|
|
Example:
A <statement> using inline parameters
<statement id=”insertProduct” parameterClass=”Product”>
insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id#, #description#)
</statement>
A <statement> using an inline parameter map with a type
<statement id=”insertProduct” parameterClass=”Product”>
insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id:int#, #description:VarChar#)
</statement>
A <statement> using an inline parameter map with a null value replacement
<statement id=”insertProduct” parameterClass=”Product”>
insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id:int:-999999#, #description:VarChar#)
</statement>
A <select> using inline parameters
<select id=”GetSimplePerson” resultClass=”SimplePerson” parameterClass=”int”>
select FirstName, LastName from Person.Contact where ContactID = #value#
</select>
5.4.2. The <parameterMaps> Element
This block is uesd to declare the parameters which has to be passed for the statement block
Example:
<parameterMap id=”insert-product-param”>
<parameter property=”description” />
<parameter property=”id”/>
</parameterMap>
<statement id=”insertProduct” parameterMap=”insert-product-param”>
insert into PRODUCT (PRD_DESCRIPTION, PRD_ID) values (?,?);
</statement>
5.5. Building a SqlMapper Instance
The framework provides service methods that you can call which read the configuration file (and any of its definition files) and builds a SqlMapper object. The SqlMapper object provides access to the rest of the framework. The SqlMapper is designed to be multi-threaded and long-lived, and so makes for a good singleton.
Code:
using IBatisNet.Common.Utilities;
using IBatisNet.DataMapper;
using IBatisNet.DataMapper.Configuration;
namespace DataMapper
{
public class Mapper
{
private static volatile ISqlMapper _mapper = null;
protected static void Configure(object obj)
{
_mapper = null;
}
protected static void InitMapper()
{
ConfigureHandler handler = new ConfigureHandler(Configure);
DomSqlMapBuilder builder = new DomSqlMapBuilder();
_mapper = builder.ConfigureAndWatch(handler);
}
public static ISqlMapper Instance()
{
if (_mapper == null)
{
lock (typeof(SqlMapper))
{
if (_mapper == null) // double-check
{
InitMapper();
}
}
}
return _mapper;
}
public static ISqlMapper Get()
{
return Instance();
}
}
}
5.6. Code to execute IBATIS.Net
Code:
The DataLayer looks like below
using System;
using System.Collections.Generic;
using System.Web;
using System.Xml;
using IBatisNet.Common;
using IBatisNet.Common.Utilities;
using IBatisNet.DataMapper;
using IBatisNet.DataMapper.Configuration;
using DataMapper;
namespace IBATIS
{
public class DataLayer
{
public static IList<PVCSummary> PVCReport(string XMLPARAM, int PAGENUMBER, string PAGING)
{
parameters pm = new parameters();
pm.XMLPARAM = XMLPARAM;
pm.PAGENUMBER = PAGENUMBER;
pm.PAGING = PAGING;
IList<PLANNEDVSCOMPLETED> objPvCReport = DataMapper.Mapper.Instance()
.QueryForList<PLANNEDVSCOMPLETED>(“PVCReport”, pm);
return objPvCReport;
}
}
public class parameters
{
public virtual string XMLPARAM { get; set; }
public virtual int PAGENUMBER { get; set; }
public virtual string PAGING { get; set; }
}
}
The codebehind of aspx page as shown below
protected void Page_Load(object sender, EventArgs e)
{
string Param = “”; //xml parameter
IList<PLANNEDVSCOMPLETED> objReport = DataLayer.PVCReport(Param, 1, “Y”);
lstvw.DataSource = objReport; //assign result object directly to listview datasource
lstvw.DataBind()
}
To generate a class and properties at run-time
To generate a class and properties at run-time.
using System;
using System.Data;
using System.Reflection;
using System.Collections.Generic;
namespace ReportEngine
{
class Program
{
static void Main(string[] args)
{
DataTable table = InputGeneration.GetTable();
//InputGeneration.DisplayTable(table);
#region “Method2 – Generate class and properties alone at runtime”
Console.WriteLine(“\n—Method2 – Generate class and properties alone at runtime————–\n”);
IEnumerable<ReportEngine.ClassAtRuntime.DynamicProperty> properties = Method2.GenerateProperties(table);
Type type = Method2.GenerateClass(properties);
//The below combination will return all non-public instance properties on the type.
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
PropertyInfo[] props = type.GetProperties(flags);
for (int i = 0; i < props.Length; i++)
{
Console.Write(“\t{0}\t”, props[i].Name);
}
Console.WriteLine(“\t”);
Method2 m2 = new Method2();
m2.AssignClassValues(type, table);
#endregion
Console.WriteLine(“\n———————————————————\n”);
Console.ReadLine();
}
}
}
InputGeneration:
using System;
using System.Data;
namespace ReportEngine
{
public static class InputGeneration
{
public static DataTable GetTable()
{
//
// Here we create a DataTable with four columns.
//
DataTable table = new DataTable();
table.Columns.Add(“Dosage”, typeof(int));
table.Columns.Add(“Drug”, typeof(string));
table.Columns.Add(“Patient”, typeof(string));
table.Columns.Add(“Date”, typeof(DateTime));
//
// Here we add five DataRows.
//
table.Rows.Add(25, “Indocin”, “David”, DateTime.Now);
table.Rows.Add(50, “Enebrel”, “Sam”, DateTime.Now);
table.Rows.Add(10, “Hydralazine”, “Christoff”, DateTime.Now);
table.Rows.Add(21, “Combivent”, “Janet”, DateTime.Now);
table.Rows.Add(100, “Dilantin”, “Melanie”, DateTime.Now);
return table;
}
public static void DisplayTable(DataTable dt)
{
if (dt.Rows.Count > 0)
{
foreach (DataColumn column in dt.Columns)
{
Console.Write(“\t{0}\t”, column.ColumnName);
}
Console.WriteLine(“\t”);
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn column in dt.Columns)
Console.Write(“\t{0}\t”, row[column]);
Console.WriteLine(“\t”);
}
}
else
Console.WriteLine(“No Current Rows Found”);
}
}
}
Method2:
using System;
using System.Data;
using System.Collections.Generic;
using ReportEngine.ClassAtRuntime;
using System.Reflection;
namespace ReportEngine
{
public class Method2
{
public static IEnumerable<DynamicProperty> GenerateProperties(DataTable table)
{
List<DynamicProperty> Properties = new List<DynamicProperty>();
foreach (DataColumn column in table.Columns)
{
Properties.Add(new DynamicProperty(column.ColumnName.ToUpper(), column.DataType));
}
return Properties;
}
public static Type GenerateClass(IEnumerable<DynamicProperty> properties)
{
Type type = Dynamic.CreateClass(properties);
return type;
}
public void AssignClassValues(Type type, DataTable table)
{
List<object> lstobj = new List<object>();
foreach (DataRow dr in table.Rows)
{
var obj = Activator.CreateInstance(type);
PropertyInfo[] props = obj.GetType().GetProperties();
for (int i = 0; i < props.Length; i++)
{
if (props[i].CanWrite)
{
try
{
if (dr[props[i].Name] != null && !dr.IsNull(props[i].Name))
{
props[i].SetValue(obj, dr[props[i].Name], null);
}
else
{
props[i].SetValue(props[i].Name, null, null);
}
}
catch // DB COLUMN does not exist for this property.
{
props[i].SetValue(props[i].Name, null, null);
}
}
}
lstobj.Add(obj);
}
}
public void ReadClassValues(List<object> lstobj)
{
foreach (object obj in lstobj)
{
}
}
public void getModelFromObject<T>(Type type, DataTable table)
{
List<T> el = new List<T>();
foreach (DataRow dr in table.Rows)
{
T item = (T)Activator.CreateInstance(type);
getObject<T>(dr, ref item, table);
T tsts = item;
((List<T>)el).Add(item);
}
}
public void getObject<T>(DataRow dr, ref T obj, DataTable dt)
{
foreach (DataColumn dc in dt.Columns)
{
if (obj.GetType().GetProperty(dc.ColumnName) != null)
{
obj.GetType().GetProperty(dc.ColumnName).SetValue(obj, dr[dc.ColumnName], null);
}
}
}
}
}
DynamicClasswithProperties:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace ReportEngine.ClassAtRuntime
{
class DynamicClasswithProperties
{
}
public abstract class DynamicClass
{
public override string ToString()
{
PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
StringBuilder sb = new StringBuilder();
sb.Append(“{“);
for (int i = 0; i < props.Length; i++)
{
if (i > 0) sb.Append(“, “);
sb.Append(props[i].Name);
sb.Append(“=”);
sb.Append(props[i].GetValue(this, null));
}
sb.Append(“}”);
return sb.ToString();
}
}
public class DynamicProperty
{
string name;
Type type;
public DynamicProperty(string name, Type type)
{
if (name == null) throw new ArgumentNullException(“name”);
if (type == null) throw new ArgumentNullException(“type”);
this.name = name;
this.type = type;
}
public string Name
{
get { return name; }
}
public Type Type
{
get { return type; }
}
}
public static class Dynamic
{
public static Type CreateClass(IEnumerable<DynamicProperty> properties)
{
return ClassFactory.Instance.GetDynamicClass(properties);
}
}
internal class Signature : IEquatable<Signature>
{
public DynamicProperty[] properties;
public int hashCode;
public Signature(IEnumerable<DynamicProperty> properties)
{
this.properties = properties.ToArray();
hashCode = 0;
foreach (DynamicProperty p in properties)
{
hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();
}
}
public override int GetHashCode()
{
return hashCode;
}
public override bool Equals(object obj)
{
return obj is Signature ? Equals((Signature)obj) : false;
}
public bool Equals(Signature other)
{
if (properties.Length != other.properties.Length) return false;
for (int i = 0; i < properties.Length; i++)
{
if (properties[i].Name != other.properties[i].Name ||
properties[i].Type != other.properties[i].Type) return false;
}
return true;
}
}
internal class ClassFactory
{
public static readonly ClassFactory Instance = new ClassFactory();
static ClassFactory() { } // Trigger lazy initialization of static fields
ModuleBuilder module;
Dictionary<Signature, Type> classes;
int classCount;
ReaderWriterLock rwLock;
private ClassFactory()
{
AssemblyName name = new AssemblyName(“DynamicClasses”);
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
#if ENABLE_LINQ_PARTIAL_TRUST
new ReflectionPermission(PermissionState.Unrestricted).Assert();
#endif
try
{
module = assembly.DefineDynamicModule(“Module”);
}
finally
{
#if ENABLE_LINQ_PARTIAL_TRUST
PermissionSet.RevertAssert();
#endif
}
classes = new Dictionary<Signature, Type>();
rwLock = new ReaderWriterLock();
}
public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
{
rwLock.AcquireReaderLock(Timeout.Infinite);
try
{
Signature signature = new Signature(properties);
Type type;
if (!classes.TryGetValue(signature, out type))
{
type = CreateDynamicClass(signature.properties);
classes.Add(signature, type);
}
return type;
}
finally
{
rwLock.ReleaseReaderLock();
}
}
Type CreateDynamicClass(DynamicProperty[] properties)
{
LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);
try
{
string typeName = “DynamicClass” + (classCount + 1);
#if ENABLE_LINQ_PARTIAL_TRUST
new ReflectionPermission(PermissionState.Unrestricted).Assert();
#endif
try
{
TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |
TypeAttributes.Public, typeof(DynamicClass));
FieldInfo[] fields = GenerateProperties(tb, properties);
GenerateEquals(tb, fields);
GenerateGetHashCode(tb, fields);
Type result = tb.CreateType();
classCount++;
return result;
}
finally
{
#if ENABLE_LINQ_PARTIAL_TRUST
PermissionSet.RevertAssert();
#endif
}
}
finally
{
rwLock.DowngradeFromWriterLock(ref cookie);
}
}
FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)
{
FieldInfo[] fields = new FieldBuilder[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
DynamicProperty dp = properties[i];
FieldBuilder fb = tb.DefineField(“_” + dp.Name, dp.Type, FieldAttributes.Private);
PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null);
MethodBuilder mbGet = tb.DefineMethod(“get_” + dp.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
dp.Type, Type.EmptyTypes);
ILGenerator genGet = mbGet.GetILGenerator();
genGet.Emit(OpCodes.Ldarg_0);
genGet.Emit(OpCodes.Ldfld, fb);
genGet.Emit(OpCodes.Ret);
MethodBuilder mbSet = tb.DefineMethod(“set_” + dp.Name,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null, new Type[] { dp.Type });
ILGenerator genSet = mbSet.GetILGenerator();
genSet.Emit(OpCodes.Ldarg_0);
genSet.Emit(OpCodes.Ldarg_1);
genSet.Emit(OpCodes.Stfld, fb);
genSet.Emit(OpCodes.Ret);
pb.SetGetMethod(mbGet);
pb.SetSetMethod(mbSet);
fields[i] = fb;
}
return fields;
}
void GenerateEquals(TypeBuilder tb, FieldInfo[] fields)
{
MethodBuilder mb = tb.DefineMethod(“Equals”,
MethodAttributes.Public | MethodAttributes.ReuseSlot |
MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(bool), new Type[] { typeof(object) });
ILGenerator gen = mb.GetILGenerator();
LocalBuilder other = gen.DeclareLocal(tb);
Label next = gen.DefineLabel();
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Isinst, tb);
gen.Emit(OpCodes.Stloc, other);
gen.Emit(OpCodes.Ldloc, other);
gen.Emit(OpCodes.Brtrue_S, next);
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Ret);
gen.MarkLabel(next);
foreach (FieldInfo field in fields)
{
Type ft = field.FieldType;
Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
next = gen.DefineLabel();
gen.EmitCall(OpCodes.Call, ct.GetMethod(“get_Default”), null);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.Emit(OpCodes.Ldloc, other);
gen.Emit(OpCodes.Ldfld, field);
gen.EmitCall(OpCodes.Callvirt, ct.GetMethod(“Equals”, new Type[] { ft, ft }), null);
gen.Emit(OpCodes.Brtrue_S, next);
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Ret);
gen.MarkLabel(next);
}
gen.Emit(OpCodes.Ldc_I4_1);
gen.Emit(OpCodes.Ret);
}
void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields)
{
MethodBuilder mb = tb.DefineMethod(“GetHashCode”,
MethodAttributes.Public | MethodAttributes.ReuseSlot |
MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(int), Type.EmptyTypes);
ILGenerator gen = mb.GetILGenerator();
gen.Emit(OpCodes.Ldc_I4_0);
foreach (FieldInfo field in fields)
{
Type ft = field.FieldType;
Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
gen.EmitCall(OpCodes.Call, ct.GetMethod(“get_Default”), null);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.EmitCall(OpCodes.Callvirt, ct.GetMethod(“GetHashCode”, new Type[] { ft }), null);
gen.Emit(OpCodes.Xor);
}
gen.Emit(OpCodes.Ret);
}
}
}
Predefined class and generate properties alone at runtime
To generate a properties at run-time and using pre-defined class.
using System;
using System.Data;
using System.Reflection;
using System.Collections.Generic;
namespace ReportEngine
{
class Program
{
static void Main(string[] args)
{
DataTable table = InputGeneration.GetTable();
//InputGeneration.DisplayTable(table);
#region “Method1 – Predefined class and generate properties alone at runtime”
Console.WriteLine(“\n—Method1 – Predefined class and generate properties alone at runtime——\n”);
List PropertyNames = Method1.GenerateProperties(table);
List DynamicClassList = Method1.GenerateClass(PropertyNames, table);
Method1.DisplayClass(DynamicClassList, PropertyNames);
#endregion
Console.WriteLine(“\n———————————————————\n”);
Console.ReadLine();
}
}
}
InputGeneration:
using System;
using System.Data;
namespace ReportEngine
{
public static class InputGeneration
{
public static DataTable GetTable()
{
//
// Here we create a DataTable with four columns.
//
DataTable table = new DataTable();
table.Columns.Add(“Dosage”, typeof(int));
table.Columns.Add(“Drug”, typeof(string));
table.Columns.Add(“Patient”, typeof(string));
table.Columns.Add(“Date”, typeof(DateTime));
//
// Here we add five DataRows.
//
table.Rows.Add(25, “Indocin”, “David”, DateTime.Now);
table.Rows.Add(50, “Enebrel”, “Sam”, DateTime.Now);
table.Rows.Add(10, “Hydralazine”, “Christoff”, DateTime.Now);
table.Rows.Add(21, “Combivent”, “Janet”, DateTime.Now);
table.Rows.Add(100, “Dilantin”, “Melanie”, DateTime.Now);
return table;
}
public static void DisplayTable(DataTable dt)
{
if (dt.Rows.Count > 0)
{
foreach (DataColumn column in dt.Columns)
{
Console.Write(“\t{0}\t”, column.ColumnName);
}
Console.WriteLine(“\t”);
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn column in dt.Columns)
Console.Write(“\t{0}\t”, row[column]);
Console.WriteLine(“\t”);
}
}
else
Console.WriteLine(“No Current Rows Found”);
}
}
}
Method1:
using System;
using System.Data;
using System.Collections.Generic;
using ReportEngine.PropertyAtRuntime;
namespace ReportEngine
{
public static class Method1
{
public static List GenerateProperties(DataTable table)
{
List PropertyNames = new List();
foreach (DataColumn column in table.Columns)
{
PropertyNames.Add(column.ColumnName.ToUpper());
}
return PropertyNames;
}
public static List GenerateClass(List PropertyNames, DataTable table)
{
List DynamicClassList = new List();
foreach (DataRow row in table.Rows)
{
var dynamicClass = new DynamicClass();
foreach (string PropertyName in PropertyNames)
{
dynamicClass.property[PropertyName] = row[PropertyName].ToString();
}
DynamicClassList.Add(dynamicClass);
}
return DynamicClassList;
}
public static void DisplayClass(List DynamicClassList, List PropertyNames)
{
foreach (string PropertyName in PropertyNames)
{
Console.Write(“{0}\t”, PropertyName);
}
Console.WriteLine(“\n”);
foreach (DynamicClass dynamicClass in DynamicClassList)
{
foreach (string PropertyName in PropertyNames)
{
Console.Write(“{0}\t”, dynamicClass.property[PropertyName]);
}
Console.WriteLine(“\n”);
}
}
}
}
DynamicClass:
using System;
namespace ReportEngine.PropertyAtRuntime
{
public class DynamicClass
{
// property is a class that will create dynamic properties at runtime
private DynamicProperty _property = new DynamicProperty();
public DynamicProperty property
{
get { return _property; }
set { _property = value; }
}
}
}
DynamicProperty:
using System;
using System.Collections.Generic;
namespace ReportEngine.PropertyAtRuntime
{
public class DynamicProperty
{
// a Dictionary that hold all the dynamic property values
private Dictionary<string, object> properties = new Dictionary<string, object>();
// the property call to get any dynamic property in our Dictionary, or “” if none found.
public object this[string name]
{
get
{
if (properties.ContainsKey(name))
{
return properties[name];
}
return “”;
}
set
{
properties[name] = value;
}
}
}
}
Group by and Sub group in Linq
Created a result set (Using IBATIS.NET Datamapper technology to load object using Stored Procedure method) as on object.
new CLASS1
You must be logged in to post a comment.