Step 5 从实体设计代码生成实体代码、实体配置文件和数据库生成脚本
5.1 至此,所有的实体的设计就完毕了。编译EntityDesigns工程。
5.2 运行dist目录中的NBear.Tools.EntityDesignToEntity.exe工具,载入EntityDesigns工程编译生成的EntityDesigns.dll。
5.3 点击Generate Entities按钮,将生成的代码保存到Entities工程中的一个名叫Entities.cs的新代码文件。并为Entities工程添加到dist\NBear.Common.dll的引用。
5.4 点击Generate Configuration按钮,将生成的代码保存到website工程下的名为EntityConfig.xml的新文件中。
5.5 点击Generate DB Script按钮,将生成的代码保存到website工程下的名为db.sql的新文件,可以在某个新建的SQL Server数据库中执行这些脚本,创建对应于所有实体的数据库脚本。
Step 6 使用实体及NBear.Data.Gateway访问数据库
6.1 现在我们就可以使用前面生成的实体了。我们先要让website工程引用Entities工程,以及dist/NBear.Data.dll。
6.2 我们还需要设置website的Web.config文件,添加一个entityConfig section以包含EntityConfig.xml这个实体配置文件,并设置数据库连接字串。下面是设置完的Web.config,注意,粗体的部分都是我们添加的代码(注意,这里的connectionstring连接到SQL Server数据库的tempdb数据库,我们需要对tempdb数据库执行5.5生成的数据库创建脚本,另外也注意修改数据库登录密码。):
<?xml version="1.0"?> <configuration> <configSections> <section name="entityConfig" type="NBear.Common.EntityConfigurationSection, NBear.Common" /> </configSections> <entityConfig> <includes> <add key="Sample Entity Config" value="~/EntityConfig.xml" /> </includes> </entityConfig> <appSettings/> <connectionStrings> <add name="DbName" connectionString="Server=(local);Database=tempdb;Uid=sa;Pwd=sa" providerName="NBear.Data.SqlServer.SqlDbProvider"/> </connectionStrings> <system.web> <compilation debug="false" /> <authentication mode="Windows" / </system.web> </configuration>
6.3 好了,现在,我们就可以随心所欲的访问数据库了。将下面的代码添加至website工程的Default.aspx.cs文件(您也可以直接打开tutorials\ ORM_Tutorial\website目录下的Default.aspx.cs,从那里复制代码)。这些代码演示了一个非常典型的创建和级联更新有复杂关系的实体的过程,并伴有详细解说。关于Gateway支持的更多方法的介绍,可以参考doc目录下的SDK类库文档。
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using Entities; using NBear.Common; using NBear.Data; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //init a Gateway, the param "tempdb" is the connectionstring name set in Web.config Gateway gateway = new Gateway("tempdb"); //youcan also use gateway = Gateway.Default, which maps to the last connectionstring in Web.config create & save a LocalUser#region create & save a LocalUser WriteLine("Create a new local user and set property values."); LocalUser newLocalUser = new LocalUser(); newLocalUser.ID = Guid.NewGuid(); newLocalUser.Password = "12345"; //by default, newUser.Birthday equals null, because it is DateTime? type, which means when saved in database, its value is dbnull. //newUser.Birthday = null //if you want to set a compoundunit property like User.Name, you must create the compoundunit type first, and then assign it to the property //you should not assign value directly to the compoundunit property's property like "newUser.Name.FirstName = XXX", //or, a compile-time warning will be thrown WriteLine("Create & set the user name."); UserName newUserName = new UserName(); newUserName.FirstName = "teddy"; newUserName.LastName = "ma"; newLocalUser.Name = newUserName; //must create the compoundunit type first, and then assign it to the property newLocalUser.Status = UserStatus.Available; //create and assign the 1 to 1 related Profile property UserProfile newUserProfile = new UserProfile(); newUserProfile.ID = Guid.NewGuid(); //create it first newUserProfile.UserID = newLocalUser.ID; newUserProfile.ProfileContent = "some sample content"; newLocalUser.Profile = newUserProfile; //assign it to the property //create two phones and assign the 1 to many related Phones property WriteLine("Create & set the local user phones"); LocalUserPhone[] newPhones = new LocalUserPhone[2]; newPhones[0] = new LocalUserPhone(); //create first phone newPhones[0].Description = "home"; newPhones[0].ID = Guid.NewGuid(); newPhones[0].UserID = newLocalUser.ID; newPhones[0].Number = "111"; newPhones[1] = new LocalUserPhone(); //create second phone newPhones[1].Description = "work"; newPhones[1].ID = Guid.NewGuid(); newPhones[1].UserID = newLocalUser.ID; newPhones[1].Number = "222"; LocalUserPhoneArrayList newPhoneList = new LocalUserPhoneArrayList(); newPhoneList.AddRange(newPhones); newLocalUser.Phones = newPhoneList; //assign it to the property //create a group and assign it to the Groups property WriteLine("Create & set the user groups."); Group newGroup = new Group(); newGroup.ID = Guid.NewGuid(); newGroup.Name = "new group"; GroupArrayList groupList = new GroupArrayList(); groupList.Add(newGroup); newLocalUser.Groups = groupList; //another way to add a item to array property //save newLocalUser WriteLine("Save the new local user."); gateway.Save<LocalUser>(newLocalUser); //do you know what is happening when saving the new local user? #endregion Check saving result#region Check saving result WriteLine(""); WriteLine("After we saved the local user."); //let find the saved local user by id first LocalUser theSavedLocalUser = gateway.Find<LocalUser>(newLocalUser.ID); if (theSavedLocalUser != null) WriteLine("We found the saved local user itself."); //a local user is also a user, right? then could we find the saved local user as a user? User theSavedLocalUserAsUser = gateway.Find<User>(newLocalUser.ID); if (theSavedLocalUser != null) WriteLine("We found the saved local user itself as a user."); //was the 1 to 1 related user profile saved on the new local user's saving? if (theSavedLocalUser.Profile != null && theSavedLocalUser.Profile.ID == newLocalUser.Profile.ID) WriteLine("We found the 1 to 1 related user profile of the saved local user was also saved."); //were the 1 to many related local user phones saved on the new local user's saving? if (theSavedLocalUser.Phones != null && theSavedLocalUser.Phones[0].ID == newLocalUser.Phones[0].ID && theSavedLocalUser.Phones[1].ID == newLocalUser.Phones[1].ID) WriteLine("We found the 1 to many related local user phones of the saved local user were also saved."); //were the many to many related user group and the usergroup relation entity saved on the new local user's saving? if (theSavedLocalUser.Groups != null && theSavedLocalUser.Groups.Count > 0 && theSavedLocalUser.Groups[0].ID == newLocalUser.Groups[0].ID) WriteLine("We found the many to many related local user group of the saved local user was also saved."); //is the line really executed?? it should not. else WriteLine("Oh! many to many related local user group of the saved local user was NOT saved!! Do you know why? - It is NOT because it is many to many related while profile and phones are 1 to 1 or 1 to many. It is not because you are not Teddy, either. :) It IS because in the entity design of User, the Groups property is NOT marked with the [Contained] attribute."); //save an uncontained property's value WriteLine("To save an uncontained property value, such as user's Groups, you have to manually do this."); WriteLine("Firstly, you should save the group it self."); gateway.Save<Group>(newGroup); WriteLine("Furthermore, you have to create & save a usergroup relation entity manually. Let's do it."); UserGroup newUserGroup = new UserGroup(); //create the new usergroup relation entity instance newUserGroup.UserID = theSavedLocalUser.ID; newUserGroup.GroupID = newGroup.ID; gateway.Save<UserGroup>(newUserGroup); //do the saving WriteLine("Let's find the saved local user again. Was the group saved this time?"); theSavedLocalUser = gateway.Find<LocalUser>(newLocalUser.ID); if (theSavedLocalUser.Groups != null && theSavedLocalUser.Groups.Count > 0 && theSavedLocalUser.Groups[0].ID == newLocalUser.Groups[0].ID) WriteLine("Yes, conguratulation! This time, we found the many to many related local user group of the saved local user was finally saved."); //to see the saved user name details WriteLine("Do you want to know the saved user name's details, which is a compoundunit property? Ok, show you what you want, in fact, it is serialized as xml by the NBear.Common.SerializationManager class, looks like:"); WriteLine(SerializationManager.Serialize(theSavedLocalUser.Name)); WriteLine("Ok, I heard you considering whether you can save it into some other format because you do not want it to be XML? You do have chance to control this!!"); WriteLine("What youshould do is easily register a custom serialize/deserialize delegate method pair."); SerializationManager.RegisterSerializeHandler(typeof(UserName), new SerializationManager.TypeSerializeHandler(CustomSerializeUserName), new SerializationManager.TypeDeserializeHandler(CustomDeserializeUserName)); WriteLine("Let's save the user name again."); theSavedLocalUser.Name = newUserName; gateway.Save<LocalUser>(theSavedLocalUser); WriteLine("What does the details of the user name now become? It becomes:"); WriteLine(SerializationManager.Serialize(theSavedLocalUser.Name)); WriteLine("Cool!~~ Right? But remember, in real project, you must register the custom serialize/deserialize delegate method pair at application started up. For example, in Application_Start()."); WriteLine("Thank you so much for having completed this tutorial. You can look up the appendixes, for more information about the usage of the Gateway."); WriteLine("See you later!"); WriteLine("Warm regards,"); WriteLine("Teddy " + DateTime.Now.ToShortDateString()); SerializationManager.UnregisterSerializeHandler(typeof(UserName)); #endregion } private void WriteLine(string str) { Response.Write(Server.HtmlEncode(str) + "<br /><br />"); } private string CustomSerializeUserName(object name) { UserName userName = (UserName)name; return userName.FirstName + "," + userName.LastName; } private object CustomDeserializeUserName(string data) { string[] splittedData = data.Split(','); UserName userName = new UserName(); userName.FirstName = splittedData[0]; userName.LastName = splittedData[1]; return userName; } }