惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
Last Week in AI
Last Week in AI
罗磊的独立博客
量子位
Jina AI
Jina AI
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
美团技术团队
雷峰网
雷峰网
爱范儿
爱范儿
S
SegmentFault 最新的问题
小众软件
小众软件
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

博客园 - JerryZhao

[转载]jQuery对象VS DOM对象 [Reference] Navigation on Matrix Subtotal [Refereces]Creating an .ini File for the Application Manager [Refereces] Developing and Deploying Pocket PC Setup Applications [References]More on device app installs - Installing a Windows Mobile device application from a desktop MSI [References]Deploying .NET Compact Framework 2.0 Applications with .cab and .msi Files [References]Installing Multiple CAB Files [Reference]Wix Restart IIS code snippet [Reference] Windows Installer XML (WiX) 3.0 Snippets [Reference] Casle Demo App: Midway Summary [ActiveRecord] 之五:ActiveRecordMediator [Reference][ActiveRecord] 之四:Cascade [Reference][ActiveRecord] 之六:继承 [Referece][ActiveRecord] 之七:多数据库配置 [Reference][Castle AR] 3. Validate [Reference][Castle AR] 2. ActiveRecord [Reference][Castle AR] 1. Starter [reference][Castle AR] 4. CRUD [Reference]NHibernateDataSource: A DataSourceControl for ASP.NET 2.0
[Reference] [Castle AR] 5. Base Relations
JerryZhao · 2008-01-23 · via 博客园 - JerryZhao

http://www.rainsts.net/article.asp?id=487
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。