• [ActiveRecord] 之 实体映射


    Castle ActiveRecord 通过特性处理数据表关联关系。

    • Many-to-one: BelongsToAttribute
    • One-to-many: HasManyAttribute
    • Many-to-many: HasAndBelongsToManyAttribute

    1. One-to-Many / Many-to-One

    多数时候,Many-to-One 和 One-To-Many 总算相伴而生的。在下面的例子中,每个组可以有多个用户加入。我们通过在 User 类型里面使用 BelongsTo 添加一个名为 "GroupId" 的字段来处理 Many-to-One 的关联,而在 Group 中我们使用 HasMany 处理 One-to-Many。注意 HasMany 的参数,分别是 "User 类型对象","BelongsTo 所定义的字段名",以及 "User 的表名"。当然,我们可以直接缩写成 HasMany(typeof(User), "GroupId", "Users") 。

    [ActiveRecord("Groups")]
    public class Group : ActiveRecordBase<Group>
    {
      private int id;

      [PrimaryKey(PrimaryKeyType.Identity)]
      public int Id
      {
        get { return id; }
        set { id = value; }
      }

      private string name;

      [Property(Unique = true, NotNull = true)]
      public string Name
      {
        get { return name; }
        set { name = value; }
      }

      private IList users = new List<User>();

      [HasMany(typeof(User), ColumnKey = "GroupId", Table = "Users")]
      public IList Users
      {
        get { return users; }
        set { users = value; }
      }
    }

    [ActiveRecord("Users")]
    public class User : ActiveRecordBase<User>
    {
      private int id;

      [PrimaryKey(PrimaryKeyType.Identity)]
      public int Id
      {
        get { return id; }
        set { id = value; }
      }

      private string name;

      [Property(Unique = true, NotNull = true)]
      public string Name
      {
        get { return name; }
        set { name = value; }
      }

      private Group group;

      [BelongsTo("GroupId")]
      public Group Group
      {
        get { return group; }
        set { group = value; }
      }
    }

    public class ARTester
    {
      public static void Test()
      {
        ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(), new XmlConfigurationSource("ar.xml"));
        ActiveRecordStarter.DropSchema();
        ActiveRecordStarter.CreateSchema();

        Group group = new Group();
        group.Name = "Group1";
        group.Save();

        for (int i = 0; i < 10; i++)
        {
          User user = new User();
          user.Name = "User" + i;
          user.Group = group;
          user.Save();
        }

        // ---------------

        foreach (User _user in Group.FindAllByProperty("Name", "Group1")[0].Users)
        {
          Console.WriteLine("{0},{1}", _user.Name, _user.Group.Name);
        }
      }
    }


    数据表关系图

    uploads/200705/14_111952_ar_rel_1.gif



    Group 表

    uploads/200705/14_111957_ar_rel_2.gif



    User 表

    uploads/200705/14_112000_ar_rel_3.gif



    如果我们想将 HasMany 改成强类型,需要额外下载 NHibernate Generics,详细代码可参考 "Generics support"。

    2. Many-to-Many

    Many-to-Many 是通过额外的映射表来建立关联关系的。注意 HasAndBelongsToMany 的参数,分别是 "关联目标类型"、"映射表名"、"本类型在映射表中主键字段名(ColumnKey)"、"关联类型在映射表中主键字段名(ColumnRef)"。两个关联类型的相关参数必须一致。

    我们修改一下上面的例子,让用户可以同时加入多个组,这样就实现了 Many-to-Many 的需求。

    [ActiveRecord("Groups")]
    public class Group : ActiveRecordBase<Group>
    {
      private int id;

      [PrimaryKey(PrimaryKeyType.Identity)]
      public int Id
      {
        get { return id; }
        set { id = value; }
      }

      private string name;

      [Property(Unique = true, NotNull = true)]
      public string Name
      {
        get { return name; }
        set { name = value; }
      }

      private IList users = new List<User>();

      [HasAndBelongsToMany(typeof(User), Table = "UserGroup", ColumnKey = "GroupId", ColumnRef = "UserId")]
      public IList Users
      {
        get { return users; }
        set { users = value; }
      }
    }

    [ActiveRecord("Users")]
    public class User : ActiveRecordBase<User>
    {
      private int id;

      [PrimaryKey(PrimaryKeyType.Identity)]
      public int Id
      {
        get { return id; }
        set { id = value; }
      }

      private string name;

      [Property(Unique = true, NotNull = true)]
      public string Name
      {
        get { return name; }
        set { name = value; }
      }

      private IList groups;

      [HasAndBelongsToMany(typeof(Group), Table = "UserGroup", ColumnKey = "UserId", ColumnRef = "GroupId")]
      public IList Groups
      {
        get { return groups; }
        set { groups = value; }
      }
    }

    public class ARTester
    {
      public static void Test()
      {
        ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(), new XmlConfigurationSource("ar.xml"));
        ActiveRecordStarter.DropSchema();
        ActiveRecordStarter.CreateSchema();

        for (int i = 0; i < 10; i++)
        {
          User user = new User();
          user.Name = "User" + i;
          user.Save();
        }

        for (int i = 0; i < 10; i++)
        {
          Group group = new Group();
          group.Name = "Group" + i;
          group.Save();
        }

        User user1 = User.FindAllByProperty("Name", "User1")[0];
        user1.Groups.Add(Group.FindAllByProperty("Name", "Group1")[0]);
        user1.Groups.Add(Group.FindAllByProperty("Name", "Group2")[0]);
        user1.Groups.Add(Group.FindAllByProperty("Name", "Group3")[0]);
        user1.Save();

        Group group1 = Group.FindAllByProperty("Name", "Group1")[0];
        group1.Users.Add(User.FindAllByProperty("Name", "User7")[0]);
        group1.Users.Add(User.FindAllByProperty("Name", "User8")[0]);
        group1.Save();

        // ------------

        foreach (Group g in User.FindAllByProperty("Name", "User1")[0].Groups)
        {
          Console.WriteLine(g.Name);
        }

        foreach (User u in Group.FindAllByProperty("Name", "Group1")[0].Users)
        {
          Console.WriteLine(u.Name);
        }
      }
    }


    数据表关系图

    uploads/200705/14_112004_ar_rel_4.gif



    User 表

    uploads/200705/14_112008_ar_rel_5.gif



    Group 表

    uploads/200705/14_112011_ar_rel_6.gif



    UserGroup 表

    uploads/200705/14_112015_ar_rel_7.gif



    通过上面的图,我们发现 "ActiveRecordStarter.CreateSchema()" 创建的映射表(UserGroup)并不会创建组合主键,加上我们使用 IList 存储关联对象,因此可能会出现关联对象重复问题。解决的方法是使用自定义类型或者字典来替换 IList。

  • 相关阅读:
    软件编写和设计中的18大原则
    Ubuntu CTRL+ALT+F1~F6 进入命令模式后不支持中文显示的解决办法
    BM串匹配算法
    KMP串匹配算法解析与优化
    mongodb随机查询一条记录的正确方法!
    这真的该用try-catch吗?
    计算机的本质与数值、文字、声音、图像
    编程语言的概念
    linux服务方式启动程序脚本(init.d脚本)
    linux的7种运行级别
  • 原文地址:https://www.cnblogs.com/easyleo/p/3193876.html
Copyright © 2020-2023  润新知